<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> 
<base href="https://wiki.asterisk.org/wiki" /> 
<title>Message Title</title>  
<style type="text/css">@media only screen and (max-device-width: 480px) {.mobile-only {
        width: auto !important;
        height: auto !important;
        overflow: visible !important;
        line-height: normal !important;
        font-size: inherit !important;
        mso-hide: all;
}

.desktop-only {
        display: none !important;
}

/* iPhone 3GS fix for unwanted 20px right margin */
body { min-width: 100% !important; padding: 0; margin: 0; }

#center-content-table { max-width: none; !important; }
#header-pattern-container { padding: 10px 10px 10px 10px !important; line-height: 20px !important; }
#header-avatar-image-container { padding-right: 8px !important; }
#email-content-container { padding: 0 !important; }
.mobile-expand { border-radius: 0 !important; border-left: 0 !important; border-right: 0 !important; padding-left: 26px !important;}
.mobile-resize-text { font-size: 16px !important; line-height: 22px !important; }
#page-title-pattern-header { font-size: 20px !important; line-height: 28px !important; }
#page-title-pattern-icon-image-container-cell { padding-top: 7px !important; }
#inline-user-pattern { display: block !important; }
#inline-user-pattern-avatar { padding-top: 3px !important; }
.contextual-area-pattern { border-bottom: 1px solid #ccc !important; padding: 15px 10px 0 10px !important;}
.users-involved-pattern-column-table { width: 100% !important;  }
.users-involved-pattern-avatar-table-cell { padding: 3px 5px 5px 0 !important; }
.users-involved-pattern-column-container { padding-right: 0 !important; }
.contextual-excerpt-pattern, #users-involved-pattern { border: 0 !important; }

/** Aui Typography upsized for mobile **/
#content-excerpt-pattern-container, #contextual-excerpt-pattern-text-container { font-size: 16px !important; line-height: 22px !important; }
#content-excerpt-pattern-container h1, #contextual-excerpt-pattern-text-container h1 { font-size: 24px !important; line-height: 28px !important; }
#content-excerpt-pattern-container h2, #contextual-excerpt-pattern-text-container h2 { font-size: 20px !important; line-height: 28px !important; }
#content-excerpt-pattern-container h3, #contextual-excerpt-pattern-text-container h3 { font-size: 18px !important; line-height: 24px !important; }
#content-excerpt-pattern-container h4, #contextual-excerpt-pattern-text-container h4 { font-size: 16px !important; line-height: 22px !important; }
#content-excerpt-pattern-container h5, #contextual-excerpt-pattern-text-container h5 { font-size: 14px !important; line-height: 20px !important; }
#content-excerpt-pattern-container h6, #contextual-excerpt-pattern-text-container h6 { font-size: 14px !important; line-height: 20px !important; }
.user-mention { line-height: 18px !important; }
/** Aui Typography end **/

/* Show appropriate footer logo on mobile, display links vertically */
#footer-pattern { padding: 15px 10px !important; }
#footer-pattern-logo-desktop-container { padding: 0 !important; }
#footer-pattern-logo-desktop { width: 0 !important; height: 0 !important; }
#footer-pattern-logo-mobile {
    padding-top: 10px !important;
    width: 30px !important;
    height: 27px !important;
    display: inline !important;
}
#footer-pattern-text {
    display: block !important;
}
#footer-pattern-links-container { line-height: 0 !important;}
.footer-pattern-links.mobile-resize-text,
.footer-pattern-links.mobile-resize-text,
#footer-pattern-text.mobile-resize-text,
#footer-pattern-links-container.no-footer-links {
    font-size: 14px !important;
    line-height: 20px !important;
}
.footer-link { display: block !important; }
#footer-pattern-links-container table { display: inline-block !important; float: none !important; }
#footer-pattern-links-container, #footer-pattern-text { text-align: center !important; }
#footer-pattern-links { padding-bottom: 5px !important; }

/** Team Calendar overrides, these should be removed when notifications are updated in Team Calendars. For now CSS
    overrides are being used because the structure of the content can't change without rereleasing the plugin */
.mail-calendar-container .day-header + table tr td:first-child {
    vertical-align: top !important;
    padding-top: 5px !important;
}}
@media (min-width: 900px) {#center-content-table { width: 900px; }}
@media all {#outlook a {padding:0;} /* Force Outlook to provide a "view in browser" menu link. */
/* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
body{-webkit-text-size-adjust:100%; -ms-text-size-adjust:100%;}
.ExternalClass {width:100%;} /* Force Hotmail to display emails at full width */
#background-table {margin:0; padding:0; width:100% !important; }
/* Needed to override highlighting on date and time links in iOS */
.grey a {color: #707070; text-decoration: none; }/* These styles are appended to the head element of a notification in order to prevent Apple Mail and similar
   clients from underlining the due dates with a blue hyperlink */
/* a lozenge outside an inline task should always be #333, lozenges inside an inline task should be
   colored according to their upcoming due dates, a completed task date lozenge or deleted task date
   lozenge should always be #707070 */
.date-time-lozenge a {color: #333333; text-decoration: none; }
.inline-task-text-container .date-time-lozenge.date-upcoming a {color: #DF6F00; text-decoration: none; }
.inline-task-text-container .date-time-lozenge.date-past a {color: #D04437; text-decoration: none; }
.inline-task-text-container.content-deleted-color .date-time-lozenge a,
.inline-task-text-container.checked .date-time-lozenge a {
    color: #707070; text-decoration: none;
}}
</style> 
</head>
<body>
<table id="background-table" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; background-color: #f5f5f5"> 
<tbody> 
<tr> 
<td id="header-pattern-container" style="padding: 0px; border-collapse: collapse; padding: 10px 20px"> 
<table id="header-pattern" cellspacing="0" cellpadding="0" border="0" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td id="header-avatar-image-container" valign="top" style="padding: 0px; border-collapse: collapse; vertical-align: top; width: 32px; padding-right: 9px"><a href="https://wiki.asterisk.org/wiki/display/~mmichelson?src=email" style="color: #3b73af; text-decoration: none"><img id="header-avatar-image" class="image_fix" src="cid:avatar_99ed0aa29d6f204db4785296f8170422" height="32" width="32" border="0" style="border-radius: 3px; vertical-align: top" /></a></td>
<td id="header-text-container" valign="middle" style="padding: 0px; border-collapse: collapse; vertical-align: middle; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px">Mark Michelson <strong>edited</strong> a page</td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
<!-- End Header pattern --> 
<tr> 
<td id="email-content-container" style="padding: 0px; border-collapse: collapse; padding: 0 20px"> 
<table id="email-content-table" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; border-spacing: 0; border-collapse: separate"> 
<tbody> 
<tr> 
<td class="email-content-rounded-top mobile-expand" style="padding: 0px; border-collapse: collapse; color: #fff; padding: 0 15px 0 16px; height: 15px; background-color: #fff; border-left: 1px solid #ccc; border-top: 1px solid #ccc; border-right: 1px solid #ccc; border-bottom: 0; border-top-right-radius: 5px; border-top-left-radius: 5px"> </td> 
</tr> 
<tr> 
<td class="email-content-main mobile-expand" style="padding: 0px; border-collapse: collapse; border-left: 1px solid #ccc; border-right: 1px solid #ccc; border-top: 0; border-bottom: 0; padding: 0 15px 15px 16px; background-color: #fff"> 
<table id="page-title-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td id="page-title-pattern-icon-image-container" valign="top" style="padding: 0px; border-collapse: collapse; width: 16px; vertical-align: top"> 
<table cellspacing="0" cellpadding="0" border="0" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td id="page-title-pattern-icon-image-container-cell" style="padding: 0px; border-collapse: collapse; width: 16px; padding: 9px 8px 0px 0px; mso-text-raise: 5px; mso-line-height-rule: exactly"><a href="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=29396202&src=email" title="page icon" style="vertical-align: top;; color: #3b73af; text-decoration: none"><img style="vertical-align: top; display: block;" src="cid:page-icon" alt="page icon" title="page icon" height="16" width="16" border="0" /></a></td> 
</tr> 
</tbody> 
</table> </td>
<td style="vertical-align: top;; padding: 0px; border-collapse: collapse; padding-right: 5px; font-size: 20px; line-height: 30px; mso-line-height-rule: exactly" id="page-title-pattern-header-container"><span id="page-title-pattern-header" style="font-family: Arial, sans-serif; padding: 0; font-size: 20px; line-height: 30px; mso-text-raise: 2px; mso-line-height-rule: exactly; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=29396202&src=email" title="MEDIA? MORE LIKE MEDI-DUH!" style="color: #3b73af; text-decoration: none">MEDIA? MORE LIKE MEDI-DUH!</a></span></td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
<tr> 
<td class="email-content-main mobile-expand" style="padding: 0px; border-collapse: collapse; border-left: 1px solid #ccc; border-right: 1px solid #ccc; border-top: 0; border-bottom: 0; padding: 0 15px 15px 16px; background-color: #fff"> 
<table class="content-excerpt-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px"> 
<tbody> 
<tr> 
<td class="content-excerpt-pattern-container mobile-resize-text " style="padding: 0px; border-collapse: collapse; padding: 0 0 0 24px"> <p class="diff-context-placeholder" style="margin: 10px 0 0 0; margin-top: 0">...</p> 
<table class="diff-macro diff-block-target" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/plugins/servlet/confluence/placeholder/macro-icon?name=code" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Code Block</th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-properties" style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;padding: 0; border: 1px solid #dddddd;; padding: 0px; border-collapse: collapse"> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">title</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">event.py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">language</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">collapse</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">true</td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
<tbody> 
<tr> 
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">class Event(object):
    <span class="diff-html-added" id="added-diff-0" style="font-size: 100%; background-color: #ddfade;"># </span>DTMF<span class="diff-html-added" id="added-diff-1" style="font-size: 100%; background-color: #ddfade;"> digits
    DTMF</span>_1 = "1"
    DTMF_2 = "2"
    DTMF_3 = "3"
    DTMF_4 = "4"
    DTMF_5 = "5"
    DTMF_6 = "6"
    DTMF_7 = "7"
    DTMF_8 = "8"
    DTMF_9 = "9"
    DTMF_0 = "0"
    <span class="diff-html-added" id="added-diff-2" style="font-size: 100%; background-color: #ddfade;"># Use "octothorpe" so there is no confusion about "pound" or "hash"
    # terminology.
    </span>DTMF_OCTOTHORPE = "#"
    DTMF_STAR = "*"
    <span class="diff-html-added" id="added-diff-3" style="font-size: 100%; background-color: #ddfade;"># Call has hung up
    </span>HANGUP = "hangup"<span class="diff-html-added" id="added-diff-4" style="font-size: 100%; background-color: #ddfade;">
    # Playback of a file has completed
    PLAYBACK_COMPLETE = "playback_complete"
    # Mailbox has been emptied
    MAILBOX_EMPTY = "empty"</span>
</pre> </td> 
</tr> 
</tbody> 
</table> <p class="diff-block-context" style="margin: 10px 0 0 0">There is no hard requirement that we define events as named constants, but doing so makes it easier for tools like pylint and jslint to find potential mistakes.</p> <p class="diff-context-placeholder" style="margin: 10px 0 0 0">...</p> 
<table class="diff-macro diff-block-context" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/images/icons/macrobrowser/dropdown/panel.png" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Panel</th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-properties" style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;padding: 0; border: 1px solid #dddddd;; padding: 0px; border-collapse: collapse"> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">bgColor</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">silver</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">titleBGColor</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">seagreen</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">borderStyle</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">solid</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">title</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">Reader Exercise 5</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">titleColor</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">black</td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
<tbody> 
<tr> 
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <p style="margin: 10px 0 0 0; margin-top: 0">Our current implementation of <code style="font-family: monospace">GreetingState</code> does not take language into consideration. The <code style="font-family: monospace">sounds_installed</code> method checks for the existence of the sound file, but it does not ensure that we have the sound file in the language of the channel that is in our application.</p> <p style="margin: 10px 0 0 0">For this exercise, modify <code style="font-family: monospace">sounds_installed()</code> to also check if the retrieved sound exists in the language of the calling channel. The channel's language can be retrieved using the <code style="font-family: monospace">getChannelVar()</code> method on a channel to retrieve the value of variable "CHANNEL(language)". The sound returned by <code style="font-family: monospace">sounds.get()</code> contains an array of <code style="font-family: monospace">FormatLang</code> objects that are a pair of format and language strings. If the sound exists, but not in the channel's language, then throw an exception.</p> </td> 
</tr> 
</tbody> 
</table> <p class="diff-block-target" style="margin: 10px 0 0 0"> <span class="diff-html-removed" id="removed-diff-0" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;"> </span> </p> <h3 id="MEDIA?MORELIKEMEDI-DUH!-Controllingplaybacks" class="diff-block-context" style="margin: 10px 0 0 0; font-size: 16px; line-height: 25px; margin: 30px 0 0 0">Controlling playbacks</h3> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0">We've seen playbacks get stopped, but there are a lot more interesting operations that can be done on playbacks, such as reversing and fast-forwarding them. Within the context of recording a voicemail, these operations are pretty useless, so we will shift our focus now to the other side of voicemail: listening to recorded voicemails.</p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">For this, we will write a new application. </span>This <span class="diff-html-added" id="added-diff-6" style="font-size: 100%; background-color: #ddfade;">new application will allow a caller to listen to the voicemails that are stored in a specific mailbox. When the caller calls in, a prompt is played to the caller saying which message number the caller is hearing. When the message number finishes playing (or if the caller interrupts the playback with '#'), then the caller hears the specified message in the voicemail box. While listening to the voicemail, the caller can do several things:</span> </p> 
<ul class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '1' key to go back 3 seconds in the current message playback.</span> </li> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '2' key to pause or unpause the current message playback.</span> </li> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '3' key to go forward 3 seconds in the current message playback.</span> </li> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '4' key to play to the previous message.</span> </li> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '5' key to restart the current message playback.</span> </li> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '6' key to play to the next message.</span> </li> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '*' key to delete the current message and play the next message.</span> </li> 
<li> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Press the '#' key to end the call.</span> </li> 
</ul> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">If all messages in a mailbox are deleted or if the mailbox contained no messages to begin with, then "no more messages" is played back to the user, and the call is completed.</span> </p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">This </span>means defining a brand new state machine. To start with, we'll define a <span class="diff-html-removed" id="removed-diff-1" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">couple of </span><span class="diff-html-added" id="added-diff-7" style="font-size: 100%; background-color: #ddfade;">three new </span>states. The "preamble" state is a state where the current message number is played back to the listener. The "listening" state is where <span class="diff-html-removed" id="removed-diff-2" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">a voicemail </span><span class="diff-html-added" id="added-diff-8" style="font-size: 100%; background-color: #ddfade;">the  voice mail </span>message is played back to the listener. <span class="diff-html-added" id="added-diff-9" style="font-size: 100%; background-color: #ddfade;">The "empty" state is where no more messages remain in the mailbox. </span>Here is the state machine we will be using:</p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <span class="diff-html-removed" id="removed-diff-3" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">In addition to the state transitions that are listed, there are several other DTMF keys that may be pressed while in the "listening" state that will affect the message being played but that will not result in a state transition. We will set it up as follows:</span> </p> <p class="diff-context-placeholder" style="margin: 10px 0 0 0">...</p> <p style="text-align: center;; margin: 10px 0 0 0" class="diff-block-target diff-block-context"></p> 
<table class="diff-macro bodyless diff-html-added" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;margin: 5px 0; padding: 0; width: auto;background-color: #ddfade;border-color: #93c49f;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="diff-html-added" id="added-diff-10" style="font-size: 100%; background-color: #ddfade;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/plugins/servlet/confluence/placeholder/macro-icon?name=gliffy" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Gliffy Diagram</span></th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-properties" style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;padding: 0; border: 1px solid #dddddd;; padding: 0px; border-collapse: collapse"> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"></td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"></td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">name</span></td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">vm-listen</span></td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
</table> <p style="margin: 10px 0 0 0"></p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Notice that DMTF '4', '6', and '*' all change the state to the preamble state. This is so that the new message number can be played back to the caller before the next message is heard. Also notice that the preamble state is responsible for determining if the state should change to empty. This keeps the logic in the listening state more straight-forward since it is already having to deal with a lot of DTMF events. It also gracefully handles the case where a caller calls into the application when the caller has no voicemail messages</span><span class="diff-html-changed" id="changed-diff-0" style="background-color: #d6f0ff;">.</span> </p> <p class="diff-block-context" style="margin: 10px 0 0 0">Here is the implementation of the application.</p> 
<table class="diff-macro diff-block-target" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/plugins/servlet/confluence/placeholder/macro-icon?name=code" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Code Block</th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-properties" style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;padding: 0; border: 1px solid #dddddd;; padding: 0px; border-collapse: collapse"> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">title</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">vm-playback.py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">language</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">collapse</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">true</td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
<tbody> 
<tr> 
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">#!/usr/bin/env python

import ari
import logging
import <span class="diff-html-removed" id="removed-diff-4" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">os</span><span class="diff-html-added" id="added-diff-11" style="font-size: 100%; background-color: #ddfade;">sys</span>

from state_machine import StateMachine
from ending_state import EndingState
from hungup_state import HungUpState
from listening_state import ListeningState
from preamble_state import PreambleState
from <span class="diff-html-added" id="added-diff-12" style="font-size: 100%; background-color: #ddfade;">empty_state import EmptyState
from </span>event import Event

logging.basicConfig(level=logging.ERROR)
LOGGER = logging.getLogger(__name__)

client = ari.connect('http://10.24.20.249:8088', 'asterisk', 'asterisk')


class VoiceMailCall(object):
    def __init__(self, ari_client, channel, mailbox):
        self.client = ari_client
        self.channel = channel

       <span class="diff-html-added" id="added-diff-13" style="font-size: 100%; background-color: #ddfade;"> self.voicemails = []
        </span>recordings = ari_client.recordings.listStored()
        <span class="diff-html-removed" id="removed-diff-5" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">self.voicemails</span><span class="diff-html-added" id="added-diff-14" style="font-size: 100%; background-color: #ddfade;">vm_number</span> = <span class="diff-html-removed" id="removed-diff-6" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">[rec.json['name'] </span><span class="diff-html-added" id="added-diff-15" style="font-size: 100%; background-color: #ddfade;">1
        </span>for rec in recordings<span class="diff-html-added" id="added-diff-16" style="font-size: 100%; background-color: #ddfade;">:</span>
<span class="diff-html-removed" id="removed-diff-7" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">if</span> <span class="diff-html-removed" id="removed-diff-8" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">(</span>           <span class="diff-html-added" id="added-diff-17" style="font-size: 100%; background-color: #ddfade;">if</span> <span class="diff-html-removed" id="removed-diff-9" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;"> </span>rec.json['name'].startswith('voicemail/{0}'.format(mailbox))<span class="diff-html-removed" id="removed-diff-10" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">)]</span><span class="diff-html-added" id="added-diff-18" style="font-size: 100%; background-color: #ddfade;">:
                self.voicemails.append((vm_number, rec.json['name']))</span>
        <span class="diff-html-added" id="added-diff-19" style="font-size: 100%; background-color: #ddfade;">        vm_number += 1

        </span>self.current_voicemail = 0
        self.setup_state_machine()

    def setup_state_machine(self):
        hungup_state = HungUpState(self)
        ending_state = EndingState(self)
        listening_state = ListeningState(self)
        preamble_state = PreambleState(self)
        <span class="diff-html-added" id="added-diff-20" style="font-size: 100%; background-color: #ddfade;">empty_state</span> <span class="diff-html-added" id="added-diff-21" style="font-size: 100%; background-color: #ddfade;">= EmptyState(</span>self<span class="diff-html-added" id="added-diff-22" style="font-size: 100%; background-color: #ddfade;">)
        self</span>.state_machine = StateMachine()
        self.state_machine.add_transition(listening_state, Event.DTMF_<span class="diff-html-removed" id="removed-diff-11" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">FOUR</span><span class="diff-html-added" id="added-diff-23" style="font-size: 100%; background-color: #ddfade;">4</span>,
                                          preamble_state)
        self.state_machine.add_transition(listening_state, Event.DTMF_<span class="diff-html-removed" id="removed-diff-12" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">SIX</span><span class="diff-html-added" id="added-diff-24" style="font-size: 100%; background-color: #ddfade;">6</span>,
                                          preamble_state)
        self.state_machine.add_transition(listening_state, Event.HANGUP,
                                          hungup_state)
        self.state_machine.add_transition(listening_state, Event.DTMF_OCTOTHORPE,
                                          ending_state)
        self.state_machine.add_transition(listening_state, Event.DTMF_STAR,
                                          preamble_state)
        self.state_machine.add_transition(<span class="diff-html-removed" id="removed-diff-13" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">listening</span><span class="diff-html-added" id="added-diff-25" style="font-size: 100%; background-color: #ddfade;">preamble</span>_state, Event.<span class="diff-html-removed" id="removed-diff-14" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">EMPTY</span><span class="diff-html-added" id="added-diff-26" style="font-size: 100%; background-color: #ddfade;">DTMF_OCTOTHORPE</span>,
                                          <span class="diff-html-removed" id="removed-diff-15" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">ending</span><span class="diff-html-added" id="added-diff-27" style="font-size: 100%; background-color: #ddfade;">listening</span>_state)
        self.state_machine.add_transition(preamble_state,
<span class="diff-html-removed" id="removed-diff-16" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">Event.DTMF_OCTOTHORPE</span><span class="diff-html-added" id="added-diff-28" style="font-size: 100%; background-color: #ddfade;">                                          Event.PLAYBACK_COMPLETE</span>,
                                          listening_state)
        self.state_machine.add_transition(preamble_state, Event.<span class="diff-html-added" id="added-diff-29" style="font-size: 100%; background-color: #ddfade;">MAILBOX_EMPTY,
                                          empty_state)
        self.state_machine.add_transition(preamble_state, Event.</span>HANGUP,
                                          hungup_state)
        self.state_machine.<span class="diff-html-added" id="added-diff-30" style="font-size: 100%; background-color: #ddfade;">add_transition(empty_state, Event.HANGUP,
                                          hungup_state)
        self.state_machine.add_transition(empty_state,
                                          Event.PLAYBACK_COMPLETE,
                                          ending_state)
        self.state_machine.</span>start(preamble_state)

    def next_message(self):
        self.current_voicemail += 1
        if self.current_voicemail == len(self.voicemails):
            self.current_voicemail = 0

    def previous_message(self):
        self.current_voicemail -= 1
        if self.current_voicemail < 0:
            self.current_voicemail = len(self.voicemails) - 1

    def delete_message(self):
        del self.voicemails[self.current_voicemail]
        if <span class="diff-html-added" id="added-diff-31" style="font-size: 100%; background-color: #ddfade;">self.current_voicemail == </span>len(self.voicemails)<span class="diff-html-removed" id="removed-diff-17" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;"> == 0</span>:
            <span class="diff-html-removed" id="removed-diff-18" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">return False
</span><span class="diff-html-added" id="added-diff-32" style="font-size: 100%; background-color: #ddfade;">self.current_voicemail = 0</span>

    <span class="diff-html-removed" id="removed-diff-19" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">  if self.</span><span class="diff-html-added" id="added-diff-33" style="font-size: 100%; background-color: #ddfade;">def get_</span>current_voicemail<span class="diff-html-removed" id="removed-diff-20" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;"> == len</span><span class="diff-html-added" id="added-diff-34" style="font-size: 100%; background-color: #ddfade;">_number</span>(self<span class="diff-html-removed" id="removed-diff-21" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">.voicemails</span>):
        <span class="diff-html-added" id="added-diff-35" style="font-size: 100%; background-color: #ddfade;">return</span> <span class="diff-html-added" id="added-diff-36" style="font-size: 100%; background-color: #ddfade;">self.voicemails[self.current_voicemail][0]</span>

 <span class="diff-html-removed" id="removed-diff-22" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">self.previous_message()</span><span class="diff-html-added" id="added-diff-37" style="font-size: 100%; background-color: #ddfade;">   def get_current_voicemail_file(self):</span>
        return <span class="diff-html-removed" id="removed-diff-23" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">True</span><span class="diff-html-added" id="added-diff-38" style="font-size: 100%; background-color: #ddfade;">self.voicemails[self.current_voicemail][1]</span>

    def <span class="diff-html-removed" id="removed-diff-24" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">get</span><span class="diff-html-added" id="added-diff-39" style="font-size: 100%; background-color: #ddfade;">mailbox</span>_<span class="diff-html-removed" id="removed-diff-25" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">current</span><span class="diff-html-added" id="added-diff-40" style="font-size: 100%; background-color: #ddfade;">empty</span>(self):
        return <span class="diff-html-added" id="added-diff-41" style="font-size: 100%; background-color: #ddfade;">len(</span>self.voicemails<span class="diff-html-removed" id="removed-diff-26" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">[self.current_voicemail]

</span><span class="diff-html-added" id="added-diff-42" style="font-size: 100%; background-color: #ddfade;">) == 0


</span>def stasis_start_cb(channel_obj, event):
    channel = channel_obj['channel']
    channel_name = channel.json.get('name')
    mailbox = event.get('args')[0]
    print("Channel {0} recording voicemail for {1}".format(
        channel_name, mailbox))
    channel.answer()
    VoiceMailCall(client, channel, mailbox)
<span class="diff-html-added" id="added-diff-43" style="font-size: 100%; background-color: #ddfade;">

</span>client.on_channel_event('StasisStart', stasis_start_cb)
client.run(apps=sys.argv[1])</pre> </td> 
</tr> 
</tbody> 
</table> <p class="diff-context-placeholder" style="margin: 10px 0 0 0">...</p> 
<table class="diff-macro diff-block-target diff-block-context" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/plugins/servlet/confluence/placeholder/macro-icon?name=code" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Code Block</th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-properties" style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;padding: 0; border: 1px solid #dddddd;; padding: 0px; border-collapse: collapse"> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">title</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">preamble_state.py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">language</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">collapse</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">true</td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
<tbody> 
<tr> 
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">from event import Event
import uuid

<span class="diff-html-added" id="added-diff-44" style="font-size: 100%; background-color: #ddfade;">def sounds_installed(client):
    try:
        client.sounds.get(soundId='vm-message')
    except:
        print "Required sound 'vm-message' not installed. Aborting"
        raise                    


</span>class PreambleState(object):
    state_name = "<span class="diff-html-removed" id="removed-diff-27" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">listening</span><span class="diff-html-added" id="added-diff-45" style="font-size: 100%; background-color: #ddfade;">preamble</span>"

    def __init__(self, call):
        self.call = call
        self.hangup_event = None
        self.playback_finished = None
        self.dtmf_event = None
        self.<span class="diff-html-removed" id="removed-diff-28" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">playbacks</span><span class="diff-html-added" id="added-diff-46" style="font-size: 100%; background-color: #ddfade;">playback</span> = <span class="diff-html-removed" id="removed-diff-29" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">[]</span><span class="diff-html-added" id="added-diff-47" style="font-size: 100%; background-color: #ddfade;">None</span>
        <span class="diff-html-removed" id="removed-diff-30" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">self.current_playback = 0</span><span class="diff-html-added" id="added-diff-48" style="font-size: 100%; background-color: #ddfade;">sounds_installed(call.client)

</span>    <span class="diff-html-removed" id="removed-diff-31" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">  </span>def enter(self):
        print "Entering preamble state"
        <span class="diff-html-added" id="added-diff-49" style="font-size: 100%; background-color: #ddfade;">if </span>self.<span class="diff-html-added" id="added-diff-50" style="font-size: 100%; background-color: #ddfade;">call.mailbox_empty():
            self.call.state_machine.change_state(Event.MAILBOX_EMPTY)
            return
        self.</span>hangup_event = self.call.channel.on_event("ChannelHangupRequest",
                <span class="diff-html-added" id="added-diff-51" style="font-size: 100%; background-color: #ddfade;">                                       </span>self.on_hangup)
        self.playback_finished = self.call.client.on_event(
                'PlaybackFinished', self.on_playback_finished)
        self.dtmf_event = self.call.channel.on_event('ChannelDtmfReceived',
                                                     self.on_dtmf)
        self.<span class="diff-html-removed" id="removed-diff-32" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">start</span><span class="diff-html-added" id="added-diff-52" style="font-size: 100%; background-color: #ddfade;">initialize</span>_playbacks()

    def <span class="diff-html-removed" id="removed-diff-33" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">start</span><span class="diff-html-added" id="added-diff-53" style="font-size: 100%; background-color: #ddfade;">initialize</span>_playbacks(self):
        <span class="diff-html-removed" id="removed-diff-34" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">message</span><span class="diff-html-added" id="added-diff-54" style="font-size: 100%; background-color: #ddfade;">self.current</span>_playback = <span class="diff-html-added" id="added-diff-55" style="font-size: 100%; background-color: #ddfade;">0
        current_voicemail = self.call.get_current_voicemail_number()
        self.sounds_to_play = [
            </span>{
            <span class="diff-html-added" id="added-diff-56" style="font-size: 100%; background-color: #ddfade;">    </span>'id': str(uuid.uuid4()),
            <span class="diff-html-added" id="added-diff-57" style="font-size: 100%; background-color: #ddfade;">    </span>'media': 'sound:vm-message'
        <span class="diff-html-added" id="added-diff-58" style="font-size: 100%; background-color: #ddfade;">    </span>}<span class="diff-html-added" id="added-diff-59" style="font-size: 100%; background-color: #ddfade;">,</span>
        <span class="diff-html-removed" id="removed-diff-35" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">number_playback</span> <span class="diff-html-removed" id="removed-diff-36" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">=</span> <span class="diff-html-added" id="added-diff-60" style="font-size: 100%; background-color: #ddfade;">  </span>{
            <span class="diff-html-added" id="added-diff-61" style="font-size: 100%; background-color: #ddfade;">    </span>'id': str(uuid.uuid4()),
            <span class="diff-html-added" id="added-diff-62" style="font-size: 100%; background-color: #ddfade;">    </span>'media': 'number:{0}'.format(<span class="diff-html-removed" id="removed-diff-37" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">self.call.</span>current_voicemail<span class="diff-html-added" id="added-diff-63" style="font-size: 100%; background-color: #ddfade;">)</span>
<span class="diff-html-removed" id="removed-diff-38" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">+</span> <span class="diff-html-removed" id="removed-diff-39" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">1)</span>         <span class="diff-html-added" id="added-diff-64" style="font-size: 100%; background-color: #ddfade;">  </span>}
        <span class="diff-html-removed" id="removed-diff-40" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">self.playbacks.append(self.</span><span class="diff-html-added" id="added-diff-65" style="font-size: 100%; background-color: #ddfade;">]
        self.start_playback()

    def start_playback(self):
        current_sound = self.sounds_to_play[self.current_playback]
        self.playback = self.</span>call.channel.playWithId(
                playbackId=<span class="diff-html-removed" id="removed-diff-41" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">message</span><span class="diff-html-added" id="added-diff-66" style="font-size: 100%; background-color: #ddfade;">current</span>_<span class="diff-html-removed" id="removed-diff-42" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">playback</span><span class="diff-html-added" id="added-diff-67" style="font-size: 100%; background-color: #ddfade;">sound</span>['id'],
                media=<span class="diff-html-removed" id="removed-diff-43" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">message</span><span class="diff-html-added" id="added-diff-68" style="font-size: 100%; background-color: #ddfade;">current</span>_<span class="diff-html-removed" id="removed-diff-44" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">playback</span><span class="diff-html-added" id="added-diff-69" style="font-size: 100%; background-color: #ddfade;">sound</span>['media']<span class="diff-html-added" id="added-diff-70" style="font-size: 100%; background-color: #ddfade;">
        </span>)<span class="diff-html-added" id="added-diff-71" style="font-size: 100%; background-color: #ddfade;">

    def cleanup(self</span>)<span class="diff-html-added" id="added-diff-72" style="font-size: 100%; background-color: #ddfade;">:</span>
        self.<span class="diff-html-removed" id="removed-diff-45" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">playbacks</span><span class="diff-html-added" id="added-diff-73" style="font-size: 100%; background-color: #ddfade;">playback_finished</span>.<span class="diff-html-removed" id="removed-diff-46" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">append(self.call.channel.playWithId(</span><span class="diff-html-added" id="added-diff-74" style="font-size: 100%; background-color: #ddfade;">close()</span>
        <span class="diff-html-added" id="added-diff-75" style="font-size: 100%; background-color: #ddfade;">if</span> <span class="diff-html-added" id="added-diff-76" style="font-size: 100%; background-color: #ddfade;">self.playback:</span>
      <span class="diff-html-removed" id="removed-diff-47" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">playbackId=number_playback['id'],</span><span class="diff-html-added" id="added-diff-77" style="font-size: 100%; background-color: #ddfade;">      self.playback.stop()</span>
        <span class="diff-html-added" id="added-diff-78" style="font-size: 100%; background-color: #ddfade;">self.dtmf_event.close()</span>
       <span class="diff-html-removed" id="removed-diff-48" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">media=number_playback['media']))</span><span class="diff-html-added" id="added-diff-79" style="font-size: 100%; background-color: #ddfade;"> self.hangup_event.close()</span>

    def <span class="diff-html-removed" id="removed-diff-49" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">stop</span><span class="diff-html-added" id="added-diff-80" style="font-size: 100%; background-color: #ddfade;">on</span>_<span class="diff-html-removed" id="removed-diff-50" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">playbacks</span><span class="diff-html-added" id="added-diff-81" style="font-size: 100%; background-color: #ddfade;">hangup</span>(self<span class="diff-html-added" id="added-diff-82" style="font-size: 100%; background-color: #ddfade;">, channel, event</span>):
        <span class="diff-html-removed" id="removed-diff-51" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">for </span><span class="diff-html-added" id="added-diff-83" style="font-size: 100%; background-color: #ddfade;">self.</span>playback <span class="diff-html-removed" id="removed-diff-52" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">in self.playbacks:</span><span class="diff-html-added" id="added-diff-84" style="font-size: 100%; background-color: #ddfade;">= None
        self.cleanup()</span>
        <span class="diff-html-added" id="added-diff-85" style="font-size: 100%; background-color: #ddfade;">self.call.state_machine.change_state(Event.HANGUP)</span>

  <span class="diff-html-removed" id="removed-diff-53" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">try</span><span class="diff-html-added" id="added-diff-86" style="font-size: 100%; background-color: #ddfade;">  def on_playback_finished(self, event)</span>:
        <span class="diff-html-added" id="added-diff-87" style="font-size: 100%; background-color: #ddfade;">current_sound</span> <span class="diff-html-added" id="added-diff-88" style="font-size: 100%; background-color: #ddfade;">=</span> <span class="diff-html-added" id="added-diff-89" style="font-size: 100%; background-color: #ddfade;">self.sounds_to_play[self.current_playback]</span>
     <span class="diff-html-added" id="added-diff-90" style="font-size: 100%; background-color: #ddfade;">   if current_sound['id'] == event.get('</span>playback<span class="diff-html-added" id="added-diff-91" style="font-size: 100%; background-color: #ddfade;">')</span>.<span class="diff-html-removed" id="removed-diff-54" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">stop</span><span class="diff-html-added" id="added-diff-92" style="font-size: 100%; background-color: #ddfade;">get</span>(<span class="diff-html-added" id="added-diff-93" style="font-size: 100%; background-color: #ddfade;">'id'</span>)<span class="diff-html-added" id="added-diff-94" style="font-size: 100%; background-color: #ddfade;">:</span>
            <span class="diff-html-removed" id="removed-diff-55" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">except:</span><span class="diff-html-added" id="added-diff-95" style="font-size: 100%; background-color: #ddfade;">self.playback</span> <span class="diff-html-added" id="added-diff-96" style="font-size: 100%; background-color: #ddfade;">=</span> <span class="diff-html-added" id="added-diff-97" style="font-size: 100%; background-color: #ddfade;">None</span>
            <span class="diff-html-added" id="added-diff-98" style="font-size: 100%; background-color: #ddfade;">self.current_playback</span> <span class="diff-html-added" id="added-diff-99" style="font-size: 100%; background-color: #ddfade;">+=</span> <span class="diff-html-removed" id="removed-diff-56" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">pass</span><span class="diff-html-added" id="added-diff-100" style="font-size: 100%; background-color: #ddfade;">1</span>
     <span class="diff-html-removed" id="removed-diff-57" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">def</span> <span class="diff-html-removed" id="removed-diff-58" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">cleanup(self):</span>      <span class="diff-html-added" id="added-diff-101" style="font-size: 100%; background-color: #ddfade;">if</span> <span class="diff-html-added" id="added-diff-102" style="font-size: 100%; background-color: #ddfade;">self.current_playback</span> <span class="diff-html-added" id="added-diff-103" style="font-size: 100%; background-color: #ddfade;">==</span> <span class="diff-html-added" id="added-diff-104" style="font-size: 100%; background-color: #ddfade;">len(</span>self.<span class="diff-html-removed" id="removed-diff-59" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">playback_finished.close()</span><span class="diff-html-added" id="added-diff-105" style="font-size: 100%; background-color: #ddfade;">sounds_to_play):</span>
        <span class="diff-html-added" id="added-diff-106" style="font-size: 100%; background-color: #ddfade;">        </span>self.<span class="diff-html-removed" id="removed-diff-60" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">stop_playbacks</span><span class="diff-html-added" id="added-diff-107" style="font-size: 100%; background-color: #ddfade;">cleanup</span>()
        <span class="diff-html-added" id="added-diff-108" style="font-size: 100%; background-color: #ddfade;">        </span>self.<span class="diff-html-removed" id="removed-diff-61" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">dtmf</span><span class="diff-html-added" id="added-diff-109" style="font-size: 100%; background-color: #ddfade;">call.state</span>_<span class="diff-html-removed" id="removed-diff-62" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">event</span><span class="diff-html-added" id="added-diff-110" style="font-size: 100%; background-color: #ddfade;">machine</span>.<span class="diff-html-removed" id="removed-diff-63" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">close(</span><span class="diff-html-added" id="added-diff-111" style="font-size: 100%; background-color: #ddfade;">change_state(Event.PLAYBACK_COMPLETE</span>)
        <span class="diff-html-added" id="added-diff-112" style="font-size: 100%; background-color: #ddfade;">    else:
                </span>self.<span class="diff-html-removed" id="removed-diff-64" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">hangup</span><span class="diff-html-added" id="added-diff-113" style="font-size: 100%; background-color: #ddfade;">start</span>_<span class="diff-html-removed" id="removed-diff-65" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">event.close</span><span class="diff-html-added" id="added-diff-114" style="font-size: 100%; background-color: #ddfade;">playback</span>()

    def on_<span class="diff-html-removed" id="removed-diff-66" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">hangup</span><span class="diff-html-added" id="added-diff-115" style="font-size: 100%; background-color: #ddfade;">dtmf</span>(self, channel, event):
        <span class="diff-html-added" id="added-diff-116" style="font-size: 100%; background-color: #ddfade;">digit = event.get('digit')
        if digit == '#':
            </span>self.cleanup()
        <span class="diff-html-added" id="added-diff-117" style="font-size: 100%; background-color: #ddfade;">    </span>self.call.state_machine.change_state(Event.<span class="diff-html-removed" id="removed-diff-67" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">HANGUP)

    def on_playback_finished(self, event)</span><span class="diff-html-added" id="added-diff-118" style="font-size: 100%; background-color: #ddfade;">DTMF_OCTOTHORPE)</span>
</pre> </td> 
</tr> 
</tbody> 
</table> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <code style="font-family: monospace"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">PreambleState</span></code><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;"> should look similar to the </span><code style="font-family: monospace"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">GreetingState</span></code><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;"> introduced previously. The biggest difference is that the code is structured to play multiple sound files instead of just a single one. Note that it is acceptable to call </span><code style="font-family: monospace"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">channel.play()</span></code><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;"> multiple times consecutively to queue playbacks on a channel. However, we have elected to play the second sound only after the first has completed. This is to make it easier to clean up after ourself when it is time to change states.</span> </p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Next, here is the "empty" state code:</span> </p> 
<table class="diff-macro diff-html-added diff-block-target diff-block-context" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;background-color: #ddfade;border-color: #93c49f;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/plugins/servlet/confluence/placeholder/macro-icon?name=code" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Code Block</span></th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">
<span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">from event import Event
import uuid

def sounds_installed(client):
    try:
        client.sounds.get(soundId='vm-nomore')
    except:
        print "Required sound 'vm-nomore' not installed. Aborting"
        raise


class EmptyState(object):
    state_name = "empty"

    def __init__(self, call):
        self.call = call
        self.playback_id = None
        self.hangup_event = None
        self.playback_finished = None
        self.playback = None
        sounds_installed(call.client)

    def enter(self)</span>:
        self.<span class="diff-html-removed" id="removed-diff-68" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">current_playback += 1</span><span class="diff-html-added" id="added-diff-119" style="font-size: 100%; background-color: #ddfade;">playback_id = str(uuid.uuid4())
        print "Entering empty state"
        self.hangup_event = self.call.channel.on_event("ChannelHangupRequest",
                self.on_hangup)
        self.playback_finished = self.call.client.on_event(</span>
        <span class="diff-html-removed" id="removed-diff-69" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">if </span><span class="diff-html-added" id="added-diff-120" style="font-size: 100%; background-color: #ddfade;">        'PlaybackFinished', </span>self.<span class="diff-html-removed" id="removed-diff-70" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">current</span><span class="diff-html-added" id="added-diff-121" style="font-size: 100%; background-color: #ddfade;">on</span>_playback<span class="diff-html-added" id="added-diff-122" style="font-size: 100%; background-color: #ddfade;">_finished)</span>
<span class="diff-html-added" id="added-diff-123" style="font-size: 100%; background-color: #ddfade;">        self.playback </span>=<span class="diff-html-added" id="added-diff-124" style="font-size: 100%; background-color: #ddfade;"> self.call.channel.playWithId(
                playbackId</span>=<span class="diff-html-removed" id="removed-diff-71" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;"> len(self.playbacks)</span><span class="diff-html-added" id="added-diff-125" style="font-size: 100%; background-color: #ddfade;">self.playback_id, media="sound:vm-nomore")

    def cleanup(self):
        self.playback_finished.close()
        if self.playback</span>:
            self.<span class="diff-html-added" id="added-diff-126" style="font-size: 100%; background-color: #ddfade;">playback.stop()
        self.hangup_event.close()

    def on_hangup(self, channel, event):
        # Setting playback to None stops </span>cleanup() <span class="diff-html-added" id="added-diff-127" style="font-size: 100%; background-color: #ddfade;">from</span> <span class="diff-html-added" id="added-diff-128" style="font-size: 100%; background-color: #ddfade;">trying</span> <span class="diff-html-added" id="added-diff-129" style="font-size: 100%; background-color: #ddfade;">to</span> <span class="diff-html-added" id="added-diff-130" style="font-size: 100%; background-color: #ddfade;">stop</span> <span class="diff-html-added" id="added-diff-131" style="font-size: 100%; background-color: #ddfade;">the</span>
       <span class="diff-html-added" id="added-diff-132" style="font-size: 100%; background-color: #ddfade;"> # playback.
        </span>self.<span class="diff-html-added" id="added-diff-133" style="font-size: 100%; background-color: #ddfade;">playback = None
        self.cleanup()
        self.</span>call.state_machine.change_state(Event.<span class="diff-html-removed" id="removed-diff-72" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">DTMF_OCTOTHORPE</span><span class="diff-html-added" id="added-diff-134" style="font-size: 100%; background-color: #ddfade;">HANGUP</span>)

    def on_<span class="diff-html-removed" id="removed-diff-73" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">dtmf</span><span class="diff-html-added" id="added-diff-135" style="font-size: 100%; background-color: #ddfade;">playback_finished</span>(self, <span class="diff-html-removed" id="removed-diff-74" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">channel, </span>event):
        <span class="diff-html-removed" id="removed-diff-75" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">digit =</span><span class="diff-html-added" id="added-diff-136" style="font-size: 100%; background-color: #ddfade;">if self.playback_id ==</span> event.get('<span class="diff-html-removed" id="removed-diff-76" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">digit</span><span class="diff-html-added" id="added-diff-137" style="font-size: 100%; background-color: #ddfade;">playback</span>')<span class="diff-html-added" id="added-diff-138" style="font-size: 100%; background-color: #ddfade;">.get('id'):</span>
        <span class="diff-html-removed" id="removed-diff-77" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">if</span> <span class="diff-html-removed" id="removed-diff-78" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">digit</span> <span class="diff-html-added" id="added-diff-139" style="font-size: 100%; background-color: #ddfade;">  self.playback </span>=<span class="diff-html-removed" id="removed-diff-79" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">=</span> <span class="diff-html-removed" id="removed-diff-80" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">'#':</span><span class="diff-html-added" id="added-diff-140" style="font-size: 100%; background-color: #ddfade;">None</span>
            self.cleanup()
            self.call.state_machine.change_state(Event.<span class="diff-html-removed" id="removed-diff-81" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">DTMF</span><span class="diff-html-added" id="added-diff-141" style="font-size: 100%; background-color: #ddfade;">PLAYBACK</span>_<span class="diff-html-removed" id="removed-diff-82" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">OCTOTHORPE</span><span class="diff-html-added" id="added-diff-142" style="font-size: 100%; background-color: #ddfade;">COMPLETE</span>)</pre> </td> 
</tr> 
</tbody> 
</table> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <code style="font-family: monospace"><span class="diff-html-removed" id="removed-diff-83" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">PreambleState</span></code><span class="diff-html-removed" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;"> doesn't really introduce any new concepts. What is a bit different this time is that we demonstrate that multiple playbacks can be queued at once.</span> </p> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <span class="diff-html-removed" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">Here is </span><span class="diff-html-added" id="added-diff-143" style="font-size: 100%; background-color: #ddfade;">And finally, here is </span>the "listening" state code<span class="diff-html-added" id="added-diff-144" style="font-size: 100%; background-color: #ddfade;">:</span> </p> 
<table class="diff-macro diff-block-target diff-block-context" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/plugins/servlet/confluence/placeholder/macro-icon?name=code" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Code Block</th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-properties" style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;padding: 0; border: 1px solid #dddddd;; padding: 0px; border-collapse: collapse"> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">title</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">listening_state.py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">language</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">py</td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">collapse</td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse">true</td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
<tbody> 
<tr> 
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <pre style="margin: 10px 0 0 0; margin-top: 0">from event import Event
import uuid

class ListeningState(object):
    state_name = "listening"

    def __init__(self, call):
        self.call = call
        self.playback_id = None
        self.hangup_event = None
        self.playback_finished = None
        self.dtmf_event = None
        self.playback = None

    <span class="diff-html-added" id="added-diff-145" style="font-size: 100%; background-color: #ddfade;">def</span> <span class="diff-html-removed" id="removed-diff-84" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">  self.paused = False</span><span class="diff-html-added" id="added-diff-146" style="font-size: 100%; background-color: #ddfade;">enter(self):
 </span>      <span class="diff-html-removed" id="removed-diff-85" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">def</span> <span class="diff-html-removed" id="removed-diff-86" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">enter(</span>self<span class="diff-html-removed" id="removed-diff-87" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">):</span><span class="diff-html-added" id="added-diff-147" style="font-size: 100%; background-color: #ddfade;">.paused</span> <span class="diff-html-added" id="added-diff-148" style="font-size: 100%; background-color: #ddfade;">=</span> <span class="diff-html-added" id="added-diff-149" style="font-size: 100%; background-color: #ddfade;">False</span>
      <span class="diff-html-added" id="added-diff-150" style="font-size: 100%; background-color: #ddfade;">  </span>self.playback_id = str(uuid.uuid4())
        print "Entering listening state"
        self.hangup_event = self.call.channel.on_event("ChannelHangupRequest",
                self.on_hangup)
        self.playback_finished = self.call.client.on_event(
                'PlaybackFinished', self.on_playback_finished)
        self.dtmf_event = self.call.channel.on_event('ChannelDtmfReceived',
                                                     self.on_dtmf)
        self.playback = self.call.channel.playWithId(
                playbackId=self.playback_id, media="recording:{0}".format(
                    self.call.get_current<span class="diff-html-added" id="added-diff-151" style="font-size: 100%; background-color: #ddfade;">_voicemail_file</span>()))

    def cleanup(self):
        self.playback_finished.close()
        if self.playback:
            self.playback.stop()
        self.dtmf_event.close()
        self.hangup_event.close()

    def on_hangup(self, channel, event):
        self.cleanup()
        self.call.state_machine.change_state(Event.HANGUP)

    def on_playback_finished(self, event):
        if self.playback_id == event.get('playback').get('id'):
            self.playback = None

    def on_dtmf(self, channel, event):
        digit = event.get('digit')
        if digit == '1':
            if <span class="diff-html-removed" id="removed-diff-88" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">not </span>self.playback:
                <span class="diff-html-removed" id="removed-diff-89" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">return
            </span>self.playback.control(operation='reverse')
        elif digit == '2':
            if not self.playback:
                return
            if self.paused:
                self.playback.control(operation='unpause')
                self.paused = False
            else:
                self.playback.control(operation='pause')
                self.paused = True
        elif digit == '3':
            if <span class="diff-html-removed" id="removed-diff-90" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">not </span>self.playback:
                <span class="diff-html-removed" id="removed-diff-91" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">return
            </span>self.playback.control(operation='forward')
        elif digit == '4':
            self.cleanup()
            self.call.previous_message()
            self.call.state_machine.change_state(Event.DTMF_<span class="diff-html-removed" id="removed-diff-92" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">FOUR</span><span class="diff-html-added" id="added-diff-152" style="font-size: 100%; background-color: #ddfade;">4</span>)
        elif digit == '<span class="diff-html-added" id="added-diff-153" style="font-size: 100%; background-color: #ddfade;">5':
            if self.playback:
                self.playback.control(operation='restart')
        elif digit == '</span>6':
            self.cleanup()
            self.call.next_message()
            self.call.state_machine.change_state(Event.DTMF_<span class="diff-html-removed" id="removed-diff-93" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">SIX</span><span class="diff-html-added" id="added-diff-154" style="font-size: 100%; background-color: #ddfade;">6</span>)
        elif digit == '#':
            self.cleanup()
            self.call.state_machine.change_state(Event.DTMF_OCTOTHORPE)
        elif digit == '*':
            print ("Deleting stored recording {0}".format(
                self.call.get_current<span class="diff-html-added" id="added-diff-155" style="font-size: 100%; background-color: #ddfade;">_voicemail_file</span>()))
            self.cleanup()
            self.call.client.recordings.deleteStored(
                    recordingName=self.call.get_current<span class="diff-html-added" id="added-diff-156" style="font-size: 100%; background-color: #ddfade;">_voicemail_file</span>())
            <span class="diff-html-removed" id="removed-diff-94" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">if </span>self.call.delete_message()<span class="diff-html-removed" id="removed-diff-95" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">:</span>
            <span class="diff-html-removed" id="removed-diff-96" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">    </span>self.call.state_machine.change_state(Event.DTMF_STAR)<span class="diff-html-removed" id="removed-diff-97" style="font-size: 100%; background-color: #ffe7e7; text-decoration: line-through;">
            else:
                self.call.state_machine.change_state(Event.EMPTY)</span>
</pre> </td> 
</tr> 
</tbody> 
</table> <p class="diff-block-target diff-block-context" style="margin: 10px 0 0 0"> <code style="font-family: monospace"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">ListeningState</span></code><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;"> is where we introduce new playback control concepts. The </span><code style="font-family: monospace"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">control()</span></code><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;"> method on playbacks allows for the current playback to be manipulated in various ways. All operations (reverse, pause, unpause, forward, and restart) are demonstrated here.</span> </p> 
<table class="diff-macro diff-html-added diff-block-target diff-block-context" style="background-color: #f0f0f0;border: 1px solid #dddddd;margin: 10px 1px;padding: 0 2px 2px;width: 100%;background-color: #ddfade;border-color: #93c49f;; border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<thead> 
<tr> 
<th class="diff-macro-title" style="background-color: transparent; text-align: left; font-weight: normal;padding: 5px;"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;"><span class="icon macro-placeholder-icon" style="background-color: ;line-height: 20px;"><img src="https://wiki.asterisk.org/wiki/s/en_GB/5635/60fd2eb45debbf4ede2b669f4c9b96b4ce40a937.48/_/images/icons/macrobrowser/dropdown/panel.png" style="padding-right: 5px; vertical-align: text-bottom;" /> </span>Panel</span></th> 
</tr> 
</thead> 
<tbody> 
<tr> 
<td class="diff-macro-properties" style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;padding: 0; border: 1px solid #dddddd;; padding: 0px; border-collapse: collapse"> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">bgColor</span></td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">silver</span></td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">titleBGColor</span></td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">seagreen</span></td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">borderStyle</span></td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">solid</span></td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">title</span></td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">Reader Exercise 6</span></td> 
</tr> 
<tr> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">titleColor</span></td> 
<td style="background-color: #fafafa; padding: 0 0 0 5px; font-size: 12px; text-align: left;; padding: 0px; border-collapse: collapse"><span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">black</span></td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
<tbody> 
<tr> 
<td class="diff-macro-body" style="background-color: #fff;border: 1px solid #dddddd;padding: 10px;; padding: 0px; border-collapse: collapse"> <p style="margin: 10px 0 0 0; margin-top: 0"> <span class="diff-html-added" style="font-size: 100%; background-color: #ddfade;">No idea</span> </p> </td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
<tr> 
<td class="email-content-main mobile-expand action-padding last-row-padding" style="padding: 0px; border-collapse: collapse; border-left: 1px solid #ccc; border-right: 1px solid #ccc; border-top: 0; border-bottom: 0; padding: 0 15px 15px 16px; background-color: #fff; padding-bottom: 10px; padding-bottom: 10px"> 
<table id="actions-pattern" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 1px"> 
<tbody> 
<tr> 
<td id="actions-pattern-container" valign="middle" style="padding: 0px; border-collapse: collapse; padding: 15px 0 0 24px; vertical-align: middle"> 
<table align="left" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td class="actions-pattern-action-icon-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 0px; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=29396202&src=email" title="View page Icon" style="color: #3b73af; text-decoration: none"><img class="actions-pattern-action-icon-image" height="16" width="16" border="0" title="View page Icon" src="cid:com.atlassian.confluence.plugins.confluence-email-resources%3Aview-page-email-adg-footer-item%3Aicon" alt="View page Icon" style="vertical-align: middle" /></a></td>
<td class="actions-pattern-action-text-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; padding-left: 5px; white-space: nowrap"><a href="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=29396202&src=email" title="View page" style="color: #3b73af; text-decoration: none">View page</a></td>
<td class="actions-pattern-action-bull" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; color: #999; padding: 0 5px">•</td> 
</tr> 
</tbody> 
</table> 
<table align="left" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td class="actions-pattern-action-icon-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 0px; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=29396202&showComments=true&showCommentArea=true&src=email#addcomment" title="Add comment Icon" style="color: #3b73af; text-decoration: none"><img class="actions-pattern-action-icon-image" height="16" width="16" border="0" title="Add comment Icon" src="cid:com.atlassian.confluence.plugins.confluence-email-resources%3Aadd-comment-to-content-email-adg-footer-item%3Aicon" alt="Add comment Icon" style="vertical-align: middle" /></a></td>
<td class="actions-pattern-action-text-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; padding-left: 5px; white-space: nowrap"><a href="https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=29396202&showComments=true&showCommentArea=true&src=email#addcomment" title="Add comment" style="color: #3b73af; text-decoration: none">Add comment</a></td>
<td class="actions-pattern-action-bull" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; color: #999; padding: 0 5px">•</td> 
</tr> 
</tbody> 
</table> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td class="actions-pattern-action-icon-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 0px; vertical-align: middle"><a href="https://wiki.asterisk.org/wiki/plugins/likes/like.action?contentId=29396202&src=email" title="Like Icon" style="color: #3b73af; text-decoration: none"><img class="actions-pattern-action-icon-image" height="16" width="16" border="0" title="Like Icon" src="cid:com.atlassian.confluence.plugins.confluence-like%3Aview-email-adg-content-item%3Aicon" alt="Like Icon" style="vertical-align: middle" /></a></td>
<td class="actions-pattern-action-text-container" style="padding: 0px; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly; mso-text-raise: 4px; padding-left: 5px; white-space: nowrap"><a href="https://wiki.asterisk.org/wiki/plugins/likes/like.action?contentId=29396202&src=email" title="Like" style="color: #3b73af; text-decoration: none">Like</a></td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
<tr> 
<td class="email-content-rounded-bottom mobile-expand" style="padding: 0px; border-collapse: collapse; color: #fff; height: 5px; line-height: 5px; padding: 0 15px 0 16px; background-color: #fff; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; border-top: 0; border-left: 1px solid #ccc; border-bottom: 1px solid #ccc; border-right: 1px solid #ccc; mso-line-height-rule: exactly"> </td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
<tr> 
<td id="footer-pattern" style="padding: 0px; border-collapse: collapse; padding: 12px 20px"> 
<table id="footer-pattern-container" cellspacing="0" cellpadding="0" border="0" width="100%" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333"> 
<tbody> 
<tr> 
<td id="footer-pattern-links-container" width="100%" style="padding: 0px; border-collapse: collapse; color: #999; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px"> 
<table align="left" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px"> 
<tbody> 
<tr> 
<td class="footer-pattern-links mobile-resize-text" style="padding: 0px; border-collapse: collapse"><a href="https://wiki.asterisk.org/wiki/users/removespacenotification.action?spaceKey=AST&src=email" title="" style="color: #3b73af; text-decoration: none">Stop watching space</a></td>
<td class="footer-pattern-links-bull" style="padding: 0px; border-collapse: collapse; padding: 0 5px; color: #999">•</td> 
</tr> 
</tbody> 
</table> 
<table style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px"> 
<tbody> 
<tr> 
<td class="footer-pattern-links mobile-resize-text" style="padding: 0px; border-collapse: collapse"><a href="https://wiki.asterisk.org/wiki/users/editmyemailsettings.action?src=email" title="" style="color: #3b73af; text-decoration: none">Manage notifications</a></td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
<tr> 
<td id="footer-pattern-text" class="mobile-resize-text" width="100%" style="padding: 0px; border-collapse: collapse; color: #999; font-size: 12px; line-height: 18px; font-family: Arial, sans-serif; mso-line-height-rule: exactly; mso-text-raise: 2px; display: none">This message was sent by Atlassian Confluence 5.6.1</td> 
</tr> 
</tbody> 
</table> </td> 
</tr> 
</tbody> 
</table> 
<table id="sealed-section" border="0" cellpadding="0" cellspacing="0" width="0" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; color: #333; display: none"> 
<tbody> 
<tr> 
<td style="padding: 0px; border-collapse: collapse; border: 0; font-size: 0px; line-height: 0; mso-line-height-rule: exactly"></td> 
</tr> 
</tbody> 
</table>
</body>
</html>