{"id":1182,"date":"2014-03-18T12:24:28","date_gmt":"2014-03-18T06:54:28","guid":{"rendered":"http:\/\/ramkulkarni.com\/blog\/?p=1182"},"modified":"2014-03-18T12:24:28","modified_gmt":"2014-03-18T06:54:28","slug":"cfmobile-example-record-and-playback-audio-using-coldfusion-splendor","status":"publish","type":"post","link":"http:\/\/ramkulkarni.com\/blog\/cfmobile-example-record-and-playback-audio-using-coldfusion-splendor\/","title":{"rendered":"CFMobile Example &#8211; Record and playback audio using ColdFusion Splendor"},"content":{"rendered":"<p>In this post I am going to show how easy it is to record audio and play it back in a mobile application using ColdFusion Splendor. If you haven&#8217;t already, you can download it from\u00a0<a href=\"http:\/\/labs.adobe.com\/technologies\/coldfusion\/\" target=\"_blank\">Adobe\u00a0Labs<\/a>.<\/p>\n<p>I have tried to keep the application simple. There are two buttons, Record and Play. When you click Record button, the recording starts and the Stop button is displayed. Speak into the phone\u00a0microphone\u00a0to record your voice. When done, click Stop button. You can play back the audio by clicking Play button. You can also stop playback any time by clicking Stop button.<\/p>\n<p>Here are the screen shots &#8211;<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/138.197.85.232\/blog\/wp-content\/uploads\/2014\/03\/2013_03_18_screen1.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1183\" data-permalink=\"http:\/\/ramkulkarni.com\/blog\/cfmobile-example-record-and-playback-audio-using-coldfusion-splendor\/2013_03_18_screen1\/\" data-orig-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2013_03_18_screen1.png?fit=480%2C800\" data-orig-size=\"480,800\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"2013_03_18_screen1\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2013_03_18_screen1.png?fit=180%2C300\" data-large-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2013_03_18_screen1.png?fit=480%2C800\" class=\"alignnone size-medium wp-image-1183\" style=\"border: 1px solid black;\" alt=\"2013_03_18_screen1\" src=\"https:\/\/i0.wp.com\/138.197.85.232\/blog\/wp-content\/uploads\/2014\/03\/2013_03_18_screen1-180x300.png?resize=180%2C300\" width=\"180\" height=\"300\" srcset=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2013_03_18_screen1.png?resize=180%2C300 180w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2013_03_18_screen1.png?w=480 480w\" sizes=\"(max-width: 180px) 100vw, 180px\" data-recalc-dims=\"1\" \/><\/a> <a href=\"https:\/\/i0.wp.com\/138.197.85.232\/blog\/wp-content\/uploads\/2014\/03\/2014_03_18_screen2.png\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1184\" data-permalink=\"http:\/\/ramkulkarni.com\/blog\/cfmobile-example-record-and-playback-audio-using-coldfusion-splendor\/2014_03_18_screen2\/\" data-orig-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2014_03_18_screen2.png?fit=480%2C800\" data-orig-size=\"480,800\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"2014_03_18_screen2\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2014_03_18_screen2.png?fit=180%2C300\" data-large-file=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2014_03_18_screen2.png?fit=480%2C800\" class=\"alignnone size-medium wp-image-1184\" style=\"border: 1px solid black;\" alt=\"2014_03_18_screen2\" src=\"https:\/\/i0.wp.com\/138.197.85.232\/blog\/wp-content\/uploads\/2014\/03\/2014_03_18_screen2-180x300.png?resize=180%2C300\" width=\"180\" height=\"300\" srcset=\"https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2014_03_18_screen2.png?resize=180%2C300 180w, https:\/\/i0.wp.com\/ramkulkarni.com\/blog\/wp-content\/uploads\/2014\/03\/2014_03_18_screen2.png?w=480 480w\" sizes=\"(max-width: 180px) 100vw, 180px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p><!--more-->To keep the code simple in this post, I am going to focus mainly on recording and playback of audio. The actual application also checks if the recorded file is in temporary or persistent file system. If it is in the temporary file systems, then it copies it to the persistent file system. I have already explained how to move files from temporary to persistent file system using CFClient file APIs in my post &#8211;\u00a0<a title=\"CFMobile Example \u2013 Taking picture and uploading to ColdFusion server\" href=\"http:\/\/ramkulkarni.com\/blog\/cfmobile-example-taking-picture-and-uploading-to-coldfusion-server\/\" target=\"_blank\">CFMobile Example &#8211; Taking picture and uploading to ColdFusion server<\/a>.<\/p>\n<p>When recording audio, cfclient framework first tries to find current file system (default set to persistent) and saves recorded audio file in that file system. However iOS seems to always record audio in temporary file system, irrespective of current file system set. So depending on where you run this demo application, you will see different messages.<\/p>\n<p>Let&#8217;s start with HTML and JS scripts &#8211;<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #bc7a00;\">&lt;!DOCTYPE html&gt;<\/span>\n<span style=\"color: #008000; font-weight: bold;\">&lt;meta<\/span> <span style=\"color: #7d9029;\">HTTP-EQUIV=<\/span><span style=\"color: #ba2121;\">\"PRAGMA\"<\/span> <span style=\"color: #7d9029;\">CONTENT=<\/span><span style=\"color: #ba2121;\">\"NO-CACHE\"<\/span><span style=\"color: #008000; font-weight: bold;\">&gt;<\/span>\n<span style=\"color: #008000; font-weight: bold;\">&lt;meta<\/span> <span style=\"color: #7d9029;\">name=<\/span><span style=\"color: #ba2121;\">\"viewport\"<\/span> <span style=\"color: #7d9029;\">content=<\/span><span style=\"color: #ba2121;\">\"initial-scale=1.0, user-scalable=no\"<\/span> <span style=\"color: #008000; font-weight: bold;\">\/&gt;<\/span>\n\n<span style=\"color: #008000; font-weight: bold;\">&lt;script <\/span><span style=\"color: #7d9029;\">src=<\/span><span style=\"color: #ba2121;\">\"jquery-2.0.3.min.js\"<\/span> <span style=\"color: #008000; font-weight: bold;\">&gt;&lt;\/script&gt;<\/span>\n\n<span style=\"color: #008000; font-weight: bold;\">&lt;script&gt;<\/span>\n\t$(<span style=\"color: #008000;\">document<\/span>).ready(<span style=\"color: #008000; font-weight: bold;\">function<\/span>(){\n\t\t$(<span style=\"color: #ba2121;\">\"#recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">true<\/span>);\n\t\t$(<span style=\"color: #ba2121;\">\"#playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">true<\/span>);\n\t\t$(<span style=\"color: #008000;\">document<\/span>).on(<span style=\"color: #ba2121;\">\"click\"<\/span>,<span style=\"color: #ba2121;\">\"#recordBtn\"<\/span>, onRecordBtnClicked);\n\t\t$(<span style=\"color: #008000;\">document<\/span>).on(<span style=\"color: #ba2121;\">\"click\"<\/span>,<span style=\"color: #ba2121;\">\"#playBtn\"<\/span>, onPlayBtnClicked);\n\t});\n\n\t<span style=\"color: #008000; font-weight: bold;\">function<\/span> onRecordBtnClicked()\n\t{\n\t\t<span style=\"color: #008000; font-weight: bold;\">var<\/span> btnTxt <span style=\"color: #666666;\">=<\/span> $(<span style=\"color: #ba2121;\">\"#recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"value\"<\/span>);\n\t\t<span style=\"color: #008000; font-weight: bold;\">if<\/span> (btnTxt <span style=\"color: #666666;\">==<\/span> <span style=\"color: #ba2121;\">\"Record\"<\/span>)\n\t\t\tstartRecording();\n\t\t<span style=\"color: #008000; font-weight: bold;\">else<\/span>\n\t\t\tstopRecording();\n\t}\n\n\t<span style=\"color: #008000; font-weight: bold;\">function<\/span> onPlayBtnClicked()\n\t{\n\t\t<span style=\"color: #008000; font-weight: bold;\">var<\/span> btnTxt <span style=\"color: #666666;\">=<\/span> $(<span style=\"color: #ba2121;\">\"#playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"value\"<\/span>);\n\t\t<span style=\"color: #008000; font-weight: bold;\">if<\/span> (btnTxt <span style=\"color: #666666;\">==<\/span> <span style=\"color: #ba2121;\">\"Play\"<\/span>)\n\t\t\tplayAudio();\n\t\t<span style=\"color: #008000; font-weight: bold;\">else<\/span>\n\t\t\tstopAudio();\n\t}\n<span style=\"color: #008000; font-weight: bold;\">&lt;\/script&gt;<\/span>\n\n<span style=\"color: #008000; font-weight: bold;\">&lt;h1&gt;<\/span>CFMobile Audio Demo<span style=\"color: #008000; font-weight: bold;\">&lt;\/h1&gt;<\/span>\nClick on the Record buton and speak. When done, click the Stop button.<span style=\"color: #008000; font-weight: bold;\">&lt;p&gt;<\/span>\nYou can playback recorded audio by clicking the Play button<span style=\"color: #008000; font-weight: bold;\">&lt;p&gt;<\/span>\n\n<span style=\"color: #008000; font-weight: bold;\">&lt;input<\/span> <span style=\"color: #7d9029;\">type=<\/span><span style=\"color: #ba2121;\">\"button\"<\/span> <span style=\"color: #7d9029;\">value=<\/span><span style=\"color: #ba2121;\">\"Record\"<\/span> <span style=\"color: #7d9029;\">id=<\/span><span style=\"color: #ba2121;\">\"recordBtn\"<\/span> <span style=\"color: #7d9029;\">style=<\/span><span style=\"color: #ba2121;\">\"margin-right:20px\"<\/span><span style=\"color: #008000; font-weight: bold;\">&gt;<\/span>\n<span style=\"color: #008000; font-weight: bold;\">&lt;input<\/span> <span style=\"color: #7d9029;\">type=<\/span><span style=\"color: #ba2121;\">\"button\"<\/span> <span style=\"color: #7d9029;\">value=<\/span><span style=\"color: #ba2121;\">\"Play\"<\/span> <span style=\"color: #7d9029;\">id=<\/span><span style=\"color: #ba2121;\">\"playBtn\"<\/span><span style=\"color: #008000; font-weight: bold;\">&gt;<\/span><\/pre>\n<\/div>\n<p>In document ready event, I disable record and play buttons (I enable them when cfclient is ready) and register event handlers.<\/p>\n<p>When record button is clicked (onRecordBtnClicked), I call startRecording or stopRecording functions depending on the label of the button. Similarly when play buton is clicked, I call playAudio or stopAudio. You will see all the four functions declared in cfclient block later.<br \/>\nAfter the script block I have HTML tags to display buttons.<\/p>\n<p>cfclient block starts\u00a0immediately after HTML code &#8211;<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">&lt;cfclientsettings<\/span> <span style=\"color: #7d9029;\">enabledeviceapi=<\/span><span style=\"color: #ba2121;\">\"true\"<\/span> <span style=\"color: #008000; font-weight: bold;\">&gt;<\/span>\n<span style=\"color: #008000; font-weight: bold;\">&lt;cfclient&gt;<\/span>\n\t<span style=\"color: #008000;\">&lt;cfscript&gt;<\/span>\n                <span style=\"color: #408080; font-style: italic;\">\/\/We will add cfclient code here<\/span>\n        <span style=\"color: #008000;\">&lt;\/cfscript&gt;<\/span>\n<span style=\"color: #008000; font-weight: bold;\">&lt;\/cfclient&gt;<\/span><\/pre>\n<\/div>\n<p>We need to enable device APIs because this demo uses audio APIs. Any code below below cfclientsettings tag will be executed only after all device APIs are initialized. All code in this post will now go inside cfscript block.<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\">$(<span style=\"color: #ba2121;\">\"##recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">false<\/span>);\n$(<span style=\"color: #ba2121;\">\"##playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">false<\/span>);\n\nRECORDING_STARTED <span style=\"color: #666666;\">=<\/span> <span style=\"color: #666666;\">10<\/span>;\nMEDIA_STOPPED <span style=\"color: #666666;\">=<\/span> <span style=\"color: #666666;\">4<\/span>;\nMEDIA_PAUSED <span style=\"color: #666666;\">=<\/span> <span style=\"color: #666666;\">3<\/span>;\nMEDIA_RUNNING <span style=\"color: #666666;\">=<\/span> <span style=\"color: #666666;\">2<\/span>;\nPLAYBACK_STARTED <span style=\"color: #666666;\">=<\/span> <span style=\"color: #666666;\">11<\/span>;\nMEDIA_NONE <span style=\"color: #666666;\">=<\/span> <span style=\"color: #666666;\">0<\/span>;\n\nmediaFile <span style=\"color: #666666;\">=<\/span> <span style=\"color: #008000; font-weight: bold;\">null<\/span>;\nmediaObj <span style=\"color: #666666;\">=<\/span> <span style=\"color: #008000; font-weight: bold;\">null<\/span>;\naudioStatus <span style=\"color: #666666;\">=<\/span> MEDIA_NONE;<\/pre>\n<\/div>\n<p>First, I enable Record and Play buttons, because at this point all device APIs are initialized and we can call audio APIs.<\/p>\n<p>Then I initialize a few constants for media status. Constants (values) MEDIA_STOPPED,\u00a0MEDIA_PAUSED and\u00a0MEDIA_RUNNING are defined by PhoneGap. Remaining constants are created by me for this demo.<br \/>\nI declare mediaFile variable to hold path of the recorded media file and mediaObj variable that points to PhoneGap media object. I initialize audio status to MEDIA_NONE.<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">function<\/span> mediaStatusChanged (statusArg)\n{\n\t<span style=\"color: #008000; font-weight: bold;\">switch<\/span> (statusArg)\n\t{\n\t\t<span style=\"color: #008000; font-weight: bold;\">case<\/span> <span style=\"color: #666666;\">4:<\/span> <span style=\"color: #408080; font-style: italic;\">\/\/MEDIA_STOPPED:<\/span>\n\t\t\t$(<span style=\"color: #ba2121;\">\"##recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">false<\/span>);\n\t\t\t$(<span style=\"color: #ba2121;\">\"##recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"value\"<\/span>, <span style=\"color: #ba2121;\">\"Record\"<\/span>);\n\t\t\t$(<span style=\"color: #ba2121;\">\"##playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">false<\/span>);\n\t\t\t$(<span style=\"color: #ba2121;\">\"##playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"value\"<\/span>, <span style=\"color: #ba2121;\">\"Play\"<\/span>);\n\t\t\taudioStatus <span style=\"color: #666666;\">=<\/span> MEDIA_NONE;\n\t\t\t<span style=\"color: #008000; font-weight: bold;\">break<\/span>;\n\t\t<span style=\"color: #408080; font-style: italic;\">\/\/TODO: Handle pause media status<\/span>\n\t\t<span style=\"color: #008000; font-weight: bold;\">case<\/span> <span style=\"color: #666666;\">11:<\/span> <span style=\"color: #408080; font-style: italic;\">\/\/PLAYBACK_STARTED:<\/span>\n\t\t\t$(<span style=\"color: #ba2121;\">\"##recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">true<\/span>);\n\t\t\t$(<span style=\"color: #ba2121;\">\"##playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">false<\/span>);\n\t\t\t$(<span style=\"color: #ba2121;\">\"##playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"value\"<\/span>, <span style=\"color: #ba2121;\">\"Stop\"<\/span>);\n\t\t\taudioStatus <span style=\"color: #666666;\">=<\/span> PLAYBACK_STARTED;\n\t\t\t<span style=\"color: #008000; font-weight: bold;\">break<\/span>;\n\t\t<span style=\"color: #008000; font-weight: bold;\">case<\/span> <span style=\"color: #666666;\">10:<\/span><span style=\"color: #408080; font-style: italic;\">\/\/RECORDING_STARTED:<\/span>\n\t\t\t$(<span style=\"color: #ba2121;\">\"##recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">false<\/span>);\n\t\t\t$(<span style=\"color: #ba2121;\">\"##recordBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"value\"<\/span>, <span style=\"color: #ba2121;\">\"Stop\"<\/span>);\n\t\t\t$(<span style=\"color: #ba2121;\">\"##playBtn\"<\/span>).prop(<span style=\"color: #ba2121;\">\"disabled\"<\/span>,<span style=\"color: #008000; font-weight: bold;\">true<\/span>);\n\t\t\taudioStatus <span style=\"color: #666666;\">=<\/span> RECORDING_STARTED;\n\t\t\t<span style=\"color: #008000; font-weight: bold;\">break<\/span>;\n\t}\n}<\/pre>\n<\/div>\n<p>mediaStatusChanged function is a hander function called when status of the media changes. This function just updates buttons status and sets new media status value.<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">function<\/span> startRecording()\n{\n\t<span style=\"color: #008000; font-weight: bold;\">try<\/span>\n\t{\n\t\t<span style=\"color: #008000; font-weight: bold;\">var<\/span> mediaFileName <span style=\"color: #666666;\">=<\/span> <span style=\"color: #ba2121;\">\"tempMedia.wav\"<\/span>;\n\n\t\tmediaObj <span style=\"color: #666666;\">=<\/span> cfclient.audio.createMedia(mediaFileName, <span style=\"color: #008000; font-weight: bold;\">function<\/span>(statusArg){\n\t\t\tmediaStatusChanged(statusArg);\n\t\t});\n\n\t\t<span style=\"color: #408080; font-style: italic;\">\/\/For iOS, the media file would be created in the temporary file system<\/span>\n\t\t<span style=\"color: #408080; font-style: italic;\">\/\/For Android, it will be created in the persistent file system<\/span>\n\n\t\t<span style=\"color: #408080; font-style: italic;\">\/\/start recording<\/span>\n\t\tcfclient.audio.record(mediaObj);\n\t\taudioStatus <span style=\"color: #666666;\">=<\/span> RECORDING_STARTED;\n\n\t\t<span style=\"color: #408080; font-style: italic;\">\/\/update buttons<\/span>\n\t\tmediaStatusChanged(RECORDING_STARTED);\n\t}\n\t<span style=\"color: #008000; font-weight: bold;\">catch<\/span> (any e)\n\t{\n\t\talert(<span style=\"color: #ba2121;\">\"Error recording - \"<\/span> <span style=\"color: #666666;\">+<\/span> JSON.stringify(e));\n\t}\n}<\/pre>\n<\/div>\n<p>Recording is stored in a file with name &#8220;tempMedia.wav&#8221;. If file with the same name already exists, then it is overwritten. I create media object with this file name using cfclient API createMedia. The second argument is a handler function that is called when media status changes. In this function I call the handler function I created earlier &#8211;\u00a0mediaStatusChanged.<br \/>\nOnce the media object is created successfully, I call the record function of cfclient.<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">function<\/span> stopRecording()\n{\n\t<span style=\"color: #008000; font-weight: bold;\">if<\/span> (isDefined(<span style=\"color: #ba2121;\">\"mediaObj\"<\/span>))\n\t{\n\t\tcfclient.audio.stopRecording(mediaObj);\n\t}\n}<\/pre>\n<\/div>\n<p>stopRecording function calls corresponding function of cfclient, if mediaObj is defined.<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">function<\/span> playAudio ()\n{\n\t<span style=\"color: #008000; font-weight: bold;\">if<\/span> (isDefined(<span style=\"color: #ba2121;\">\"mediaObj\"<\/span>))\n\t{\n\t\t<span style=\"color: #408080; font-style: italic;\">\/\/workaround for Android crash issue. Create media object again<\/span>\n\t\tmediaObj <span style=\"color: #666666;\">=<\/span> cfclient.audio.createMedia(mediaObj.src, <span style=\"color: #008000; font-weight: bold;\">function<\/span>(statusArg){\n\t\t\tmediaStatusChanged(statusArg);\n\t\t});\n\n\t\tcfclient.audio.play(mediaObj);\n\t\tmediaStatusChanged(PLAYBACK_STARTED);\n\t}\n\t<span style=\"color: #008000; font-weight: bold;\">else<\/span>\n\t\talert(<span style=\"color: #ba2121;\">\"No recording avilable to play\"<\/span>);\n}<\/pre>\n<\/div>\n<p>playAudio function creates media object again from the file name. This is done to work around a bug in Android. You don&#8217;t need to do this in iOS (you can reuse the media object created for recording).<br \/>\nI call play method of cfclient to playback the audio and change the media and buttons status by calling\u00a0mediaStatusChanged. When audio file is played till the end, MEDIA_STOPPED event is fired, which is handled by\u00a0mediaStatusChanged function, which updates buttons status.<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: white; overflow: auto; width: auto; color: black; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000; font-weight: bold;\">function<\/span> stopAudio()\n{\n\tcfclient.audio.stop(mediaObj);\n}<\/pre>\n<\/div>\n<p>When Stop button is clicked while media is playing, stopAudio function is called. This function calls stop method of cfclient. When media stops playing, MEDIA_STOPPED event is fired, which again is handled by\u00a0mediaStatusChanged function.<\/p>\n<p>Download <a href=\"http:\/\/ramkulkarni.com\/temp\/2014-03-18\/CFMobileAudioApp.zip\" target=\"_blank\">project files<\/a> and <a href=\"http:\/\/ramkulkarni.com\/temp\/2014-03-18\/CFMobileAudioApp.apk\" target=\"_blank\">Android APK<\/a> for this application. Note that index.cfm in this project (and application) has additional code to check if the audio file is in temporary file system and to move it to the persistent file system. Screen shots above are of application using this code. There is index2.cfm file this is not used in the packaged application, but it contains code described in this post (it does not contain file transfer code).<\/p>\n<p>-Ram Kulkarni<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post I am going to show how easy it is to record audio and play it back in a mobile application using ColdFusion Splendor. If you haven&#8217;t already, you can download it from\u00a0Adobe\u00a0Labs. I have tried to keep the application simple. There are two buttons, Record and Play. When you click Record button, &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/ramkulkarni.com\/blog\/cfmobile-example-record-and-playback-audio-using-coldfusion-splendor\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;CFMobile Example &#8211; Record and playback audio using ColdFusion Splendor&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[32,23,78,17,1],"tags":[99,94,22,24,13],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2g9O8-j4","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/1182"}],"collection":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/comments?post=1182"}],"version-history":[{"count":0,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/1182\/revisions"}],"wp:attachment":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/media?parent=1182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/categories?post=1182"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/tags?post=1182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}