Skip to main content

Twilio Video Adobe Native Extension - Getting Started with Interface - Part 1

We know Adobe AIR apps doesn't support to add native platform external SDK's directly nor we can call native API's. So we need to create an extension that will help out to do our native stuffs

For couple of months, I have been working on Adobe AIR app and now I need to integrate Twilio's video. So here I will show you how to build an adobe native extension for Android that will make Twilio video call.

First of all, we need to define extension public API wrapper or interface. This API will be accessible from AIR app. Wrapper will be build using actionscript. For wrapper, we need a package name. Here I will be using ijasnahamed.twilio.video as my package name.

Create wrapper directory

Create a directory named 'wrapper'. Here we will create our extension wrapper.

Create API class to start video

Next create a file TwilioVideo.as under ijasnahamed/twilio/video directory. Copy below code to that file

package ijasnahamed.twilio.video {
    import flash.events.EventDispatcher;
    import flash.events.StatusEvent;
    import flash.external.ExtensionContext;
    import ijasnahamed.twilio.video.events.TwilioVideoEvent;
    public class TwilioVideo extends EventDispatcher {
        private static var instance:TwilioVideo = null;
        private var context:ExtensionContext = null;
        public function TwilioVideo() {
            super();
            
            init();
        }
        public static function getInstance():TwilioVideo {
            if(instance == null) {
                instance = new TwilioVideo();
            }
            return instance;
        }
        private function init():void {
            if(context != null) {
                return;
            }
            context = ExtensionContext.createExtensionContext("ijasnahamed.twilio.video", "");
            if(context == null) {
                throw new Error("No implementation of the twilio video extension found for this platform");
            }
            context.addEventListener(StatusEvent.STATUS, function (event:StatusEvent):void {
                dispatchEvent(new TwilioVideoEvent(event.code, event.level));
            });
        }
        public function start(callDetailsAsJsonString:String):void {
            context.call("start", callDetailsAsJsonString);
}

}

}
This class will inherit EventDispatcher class because this class will catch all events from native code and dispatch that to our AIR app. Here I have used two methods

#1. Init

This is a private method and will create ExtensionContext that will create a bridge between AIR app and native code. If we doesn't have code for that phone platform, context will be null. Later this method will create an event listener that will listen for events from native side and dispatch events to our app.

#2. Start

This is a public method and we will use this method to start our video call. For now, this file will give you error because we haven't implemented TwilioVideoEvent class yet.

Create class to get library video events

Now create another file named TwilioVideoEvent.as in ijasnahamed/twilio/video/events directory from base directory. Event we send from wrapper to adobe AIR app will be of this type. Copy below code to TwilioVideoEvent.as

package ijasnahamed.twilio.video.events {
 import flash.events.Event;

 public class TwilioVideoEvent extends Event {

  public static const CALL_CONNECTED:String = "callConnected";
  public static const CALL_DISCONNECTED:String = "callDisconnected";
  public static const CALL_FAILED:String = "callFailed";
  public static const PARTICIPANT_CONNECTED:String = "participantConencted";
  public static const PARTICIPANT_DISCONNECTED:String = "participantDisconnected";
  public static const PARTICIPANT_AUDIO_TRACK_ADDED:String = "participantAudioTrackAdded";
  public static const PARTICIPANT_AUDIO_TRACK_REMOVED:String = "participantAudioTrackRemoved";
  public static const PARTICIPANT_VIDEO_TRACK_ADDED:String = "participantVideoTrackAdded";
  public static const PARTICIPANT_VIDEO_TRACK_REMOVED:String = "participantVIdeoTrackRemoved";

  private var message:String = "";

  public function TwilioVideoEvent(type:String, message:String) {
   super(type, false, false);

   this.message = message;
  }

  public function getMessage():String {
   return message;
  }
 }
} 

Create wrapper build configuration file

Now our wrapper API's are ready. Next we need to create a binary type file that will combine all this classes. For this, we use compc tool that will be available with Flex SDK. To build our binary, we need a config file of type xml where we can say our extension configuration.

Create a file named config.xml in base directory and copy below code.

<flex-config>
    <!-- Specifies the minimum player version that will run the compiled SWF. -->
     <target-player>11.1</target-player>

    <!-- Specifies the version of the compiled SWF -->
    <swf-version>14</swf-version>
    
   <compiler>

      <!-- Turn on generation of accessible SWFs. -->
      <accessible>false</accessible>
      
      <!-- Specifies the locales for internationalization. -->
      <locale>
          <locale-element>en_US</locale-element>
      </locale>

      <!-- Specifies that the target runtime is a mobile device. -->
      <mobile>true</mobile>
    
      <source-path>
        <!-- <path-element>../..</path-element> -->
        <path-element>./</path-element>
      </source-path>


      <!-- Allow the source-path to have path-elements which contain other path-elements -->
      <allow-source-path-overlap>false</allow-source-path-overlap>
      
      <!-- Run the AS3 compiler in a mode that detects legal but potentially incorrect -->
      <!-- code.                                                                       -->
      <show-actionscript-warnings>true</show-actionscript-warnings>
      
      <!-- Turn on generation of debuggable SWFs. False by default for mxmlc, -->
      <!-- but true by default for compc. -->
      <debug>true</debug>

      <!-- List of SWC files or directories to compile against but to omit from -->
      <!-- linking.                                                             -->
      <external-library-path>
         <path-element>[FLEX SDK PATH]\frameworks\libs\air\airglobal.swc</path-element>
      </external-library-path>
      
      <!-- Turn on writing of generated/*.as files to disk. These files are generated by -->
      <!-- the compiler during mxml translation and are helpful with understanding and   -->
      <!-- debugging Flex applications.                                                  -->
      <keep-generated-actionscript>false</keep-generated-actionscript>

      <!-- not set -->
      <!--
      <include-libraries>
         <library>string</library>
      </include-libraries>
      -->
      
      <!-- List of SWC files or directories that contain SWC files. -->
      <library-path>
         <path-element>[FLEX SDK PATH]\frameworks\libs</path-element>
         <path-element>[FLEX SDK PATH]\frameworks\libs\mobile</path-element>
         <path-element>[FLEX SDK PATH]\frameworks\libs\air\servicemonitor.swc</path-element>
         <path-element>[FLEX SDK PATH]\frameworks\locale\{locale}</path-element>
      </library-path>
     
      
      <!-- Enable post-link SWF optimization. -->
      <optimize>true</optimize>

      <!-- Keep the following AS3 metadata in the bytecodes.                                             -->
      <!-- Warning: For the data binding feature in the Flex framework to work properly,                 -->
      <!--          the following metadata must be kept:                                                 -->
      <!--          1. Bindable                                                                          -->
      <!--          2. Managed                                                                           -->
      <!--          3. ChangeEvent                                                                       -->
      <!--          4. NonCommittingChangeEvent                                                          -->
      <!--          5. Transient                                                                         -->
      <!--
      <keep-as3-metadata>
          <name>Bindable</name>
          <name>Managed</name>
          <name>ChangeEvent</name>
          <name>NonCommittingChangeEvent</name>
          <name>Transient</name>
      </keep-as3-metadata>
      -->
      
      <!-- Default preloader. -->
      <preloader>spark.preloaders.SplashScreen</preloader>

      <!-- Turn on reporting of data binding warnings. For example: Warning: Data binding -->
      <!-- will not be able to detect assignments to "foo".                               -->
      <show-binding-warnings>true</show-binding-warnings>
      
      <!-- toggle whether warnings generated from unused type selectors are displayed -->
      <show-unused-type-selector-warnings>true</show-unused-type-selector-warnings>

      <!-- Run the AS3 compiler in strict error checking mode. -->
      <strict>true</strict>
      
      <!-- Use the ActionScript 3 class based object model for greater performance and better error reporting. -->
      <!-- In the class based object model most built-in functions are implemented as fixed methods of classes -->
      <!-- (-strict is recommended, but not required, for earlier errors) -->
      <as3>true</as3>
      
      <!-- Use the ECMAScript edition 3 prototype based object model to allow dynamic overriding of prototype -->
      <!-- properties. In the prototype based object model built-in functions are implemented as dynamic      -->
      <!-- properties of prototype objects (-strict is allowed, but may result in compiler errors for         -->
      <!-- references to dynamic properties) -->
      <es>false</es>
      
      <!-- List of CSS or SWC files to apply as a theme. -->
      <theme>
         <!-- default theme is mobile -->
         <filename>[FLEX SDK PATH]\frameworks\themes\Mobile\mobile.swc</filename>
      </theme>
      
      <!-- Turns on the display of stack traces for uncaught runtime errors. -->
      <verbose-stacktraces>false</verbose-stacktraces>
      
      <!-- Defines the AS3 file encoding. -->
      <!-- not set -->
      <!--
      <actionscript-file-encoding></actionscript-file-encoding>
      -->
      
      <fonts>

          <!-- Enables advanced anti-aliasing for embedded fonts, which provides greater clarity for small -->
          <!-- fonts. This setting can be overriden in CSS for specific fonts. -->
          <!-- NOTE: flash-type has been deprecated. Please use advanced-anti-aliasing <flash-type>true</flash-type> -->
          <advanced-anti-aliasing>true</advanced-anti-aliasing>
        
          <!-- The number of embedded font faces that are cached. -->
          <max-cached-fonts>20</max-cached-fonts>
        
          <!-- The number of character glyph outlines to cache for each font face. -->
          <max-glyphs-per-face>1000</max-glyphs-per-face>
       
          <!-- Defines ranges that can be used across multiple font-face declarations. -->
          <!-- See flash-unicode-table.xml for more examples. -->
          <!-- not set -->
          <!--
          <languages>
              <language-range>
                  <lang>englishRange</lang>
                  <range>U+0020-U+007E</range>
              </language-range>
          </languages>
          -->
       
          <!-- Compiler font manager classes, in policy resolution order-->
          <managers>
              <manager-class>flash.fonts.JREFontManager</manager-class>
              <manager-class>flash.fonts.AFEFontManager</manager-class>
              <manager-class>flash.fonts.BatikFontManager</manager-class>
              <manager-class>flash.fonts.CFFFontManager</manager-class> 
          </managers>

          <!-- File containing cached system font licensing information produced via 
               java -cp mxmlc.jar flex2.tools.FontSnapshot (fontpath)
               Will default to winFonts.ser on Windows XP and
               macFonts.ser on Mac OS X, so is commented out by default.
          <local-fonts-snapshot>localFonts.ser</local-fonts-snapshot>
          -->
     
      </fonts> 
     
      <!-- Array.toString() format has changed. -->
      <warn-array-tostring-changes>false</warn-array-tostring-changes>
      
      <!-- Assignment within conditional. -->
      <warn-assignment-within-conditional>true</warn-assignment-within-conditional>
      
      <!-- Possibly invalid Array cast operation. -->
      <warn-bad-array-cast>true</warn-bad-array-cast>
      
      <!-- Non-Boolean value used where a Boolean value was expected. -->
      <warn-bad-bool-assignment>true</warn-bad-bool-assignment>

      <!-- Invalid Date cast operation. -->
      <warn-bad-date-cast>true</warn-bad-date-cast>
      
      <!-- Unknown method. -->
      <warn-bad-es3-type-method>true</warn-bad-es3-type-method>

      <!-- Unknown property. -->
      <warn-bad-es3-type-prop>true</warn-bad-es3-type-prop>

      <!-- Illogical comparison with NaN. Any comparison operation involving NaN will evaluate to false because NaN != NaN. -->
      <warn-bad-nan-comparison>true</warn-bad-nan-comparison>

      <!-- Impossible assignment to null. -->
      <warn-bad-null-assignment>true</warn-bad-null-assignment>

      <!-- Illogical comparison with null. -->
      <warn-bad-null-comparison>true</warn-bad-null-comparison>

      <!-- Illogical comparison with undefined. Only untyped variables (or variables of type *) can be undefined. -->
      <warn-bad-undefined-comparison>true</warn-bad-undefined-comparison>

      <!-- Boolean() with no arguments returns false in ActionScript 3.0. Boolean() returned undefined in ActionScript 2.0. -->
      <warn-boolean-constructor-with-no-args>false</warn-boolean-constructor-with-no-args>

      <!-- __resolve is no longer supported. -->
      <warn-changes-in-resolve>false</warn-changes-in-resolve>

      <!-- Class is sealed. It cannot have members added to it dynamically. -->
      <warn-class-is-sealed>true</warn-class-is-sealed>
 
      <!-- Constant not initialized. -->
      <warn-const-not-initialized>true</warn-const-not-initialized>

      <!-- Function used in new expression returns a value. Result will be what the -->
      <!-- function returns, rather than a new instance of that function.           -->
      <warn-constructor-returns-value>false</warn-constructor-returns-value>

      <!-- EventHandler was not added as a listener. -->
      <warn-deprecated-event-handler-error>false</warn-deprecated-event-handler-error>

      <!-- Unsupported ActionScript 2.0 function. -->
      <warn-deprecated-function-error>true</warn-deprecated-function-error>

      <!-- Unsupported ActionScript 2.0 property. -->
      <warn-deprecated-property-error>true</warn-deprecated-property-error>

      <!-- More than one argument by the same name. -->
      <warn-duplicate-argument-names>true</warn-duplicate-argument-names>

      <!-- Duplicate variable definition -->
      <warn-duplicate-variable-def>true</warn-duplicate-variable-def>

      <!-- ActionScript 3.0 iterates over an object's properties within a "for x in target" statement in random order. -->
      <warn-for-var-in-changes>false</warn-for-var-in-changes>

      <!-- Importing a package by the same name as the current class will hide that class identifier in this scope. -->
      <warn-import-hides-class>true</warn-import-hides-class>

      <!-- Use of the instanceof operator. -->
      <warn-instance-of-changes>true</warn-instance-of-changes>

      <!-- Internal error in compiler. -->
      <warn-internal-error>true</warn-internal-error>

      <!-- _level is no longer supported. For more information, see the flash.display package. -->
      <warn-level-not-supported>true</warn-level-not-supported>

      <!-- Missing namespace declaration (e.g. variable is not defined to be public, private, etc.). -->
      <warn-missing-namespace-decl>true</warn-missing-namespace-decl>

      <!-- Negative value will become a large positive value when assigned to a uint data type. -->
      <warn-negative-uint-literal>true</warn-negative-uint-literal>

      <!-- Missing constructor. -->
      <warn-no-constructor>false</warn-no-constructor>

      <!-- The super() statement was not called within the constructor. -->
      <warn-no-explicit-super-call-in-constructor>false</warn-no-explicit-super-call-in-constructor>

      <!-- Missing type declaration. -->
      <warn-no-type-decl>true</warn-no-type-decl>
     
      <!-- In ActionScript 3.0, white space is ignored and '' returns 0. Number() returns -->
      <!-- NaN in ActionScript 2.0 when the parameter is '' or contains white space.      -->
      <warn-number-from-string-changes>false</warn-number-from-string-changes>
      
      <!-- Change in scoping for the this keyword. Class methods extracted from an  -->
      <!-- instance of a class will always resolve this back to that instance. In   -->
      <!-- ActionScript 2.0 this is looked up dynamically based on where the method -->
      <!-- is invoked from.                                                         -->
      <warn-scoping-change-in-this>false</warn-scoping-change-in-this>
      
      <!-- Inefficient use of += on a TextField.-->
      <warn-slow-text-field-addition>true</warn-slow-text-field-addition>
     
      <!-- Possible missing parentheses. -->
      <warn-unlikely-function-value>true</warn-unlikely-function-value>
      
      <!-- Possible usage of the ActionScript 2.0 XML class. -->
      <warn-xml-class-has-changed>false</warn-xml-class-has-changed>
   
   </compiler>

   <!-- compute-digest: writes a digest to the catalog.xml of a library. Use this when the library will be used as a
                        cross-domain rsl.-->
   <!-- compute-digest usage:
   <compute-digest>boolean</compute-digest>
   -->

   <!-- A list of runtime shared library URLs to be loaded before applications start. -->
   <!-- not set -->
   <!--
   <runtime-shared-libraries>
      <url>string</url>
      <url>string</url>
   </runtime-shared-libraries>
   -->
  
  <!-- static-link-runtime-shared-libraries: statically link the libraries specified by the -runtime-shared-libraries-path option.-->
  <static-link-runtime-shared-libraries>true</static-link-runtime-shared-libraries>
   
   <!-- target-player: specifies the version of the player the application is targeting. 
                 Features requiring a later version will not be compiled into the application. 
                       The minimum value supported is "9.0.0".-->
   <!-- target-player usage:
   <target-player>version</target-player>
   -->

   <!-- Enables SWFs to access the network. -->
   <use-network>true</use-network>
   
   <!-- Metadata added to SWFs via the SWF Metadata tag. -->
   <metadata>
      <title>Twilio Video ANE</title>
      <description>Adobe AIR ANE Wrapper for Twilio Video</description>
      <publisher>Ijas N Ahamed</publisher>
      <creator>Ijas Ahamed N</creator>
      <language>EN</language>
   </metadata>

</flex-config>

Please replace [FLEX SDK PATH] with your Flex SDK path.

Build your wrapper

Now run below code to generate binary

compc -load-config config.xml -output TwilioVideo.swc -include-classes ijasnahamed.twilio.video.TwilioVideo ijasnahamed.twilio.video.events.TwilioVideoEvent

If you get any error with compc, please create an environmental variable in your PC that will points to compc.bat available in Flex_DIR/bin directory. This will create TwilioVideo.swc file which will be used to create our extension.

Get your platform library

This TwilioVideo.swc will a zip type file. Please unzip this file and you will find a library.swf file with this. We will be using this library.swf for extension packing.



Now lets build our android library from Build android library



You can get sample code for wrapper from ijasnahamed > Twilio Video ANE > wrapper

Popular posts from this blog

Setup Asterisk 13 with FreePBX 13 in CentOS 7

Launch CentOS 7 AWS Ec2 InstanceLog in to your aws consoleGo to ec2 management page and click Launch Instance on Instance pageIn Choose AMI step, go to AWS MarketPlace tab and search CentOS 7 on search field. List of centos 7 ami's will be available.Select CentOS 7 (x86_64) ami which is free tier eligible. Select your instance type and click configure instance. Keep default values from Configure Instance to Add Tags stepsIn configure security group, create a security group which allow minimum ports openSSH : port 22HTTP : port 80Custom UDP Rule : 10000-20000 (if you are giving RTP ports 10000-20000)Custom UDP Rule : 5060 (ChanSIP port)Custom TCP Rule : 5060 (ChanSIP Port)Click Launch Instance. Select your key file and accept terms to launch instance.
Setup CentOS Server SSH into newly created CentOS server with username centos and your key file.Update all existing packagessudo yum update -yNow start http service(you can access your server via browser by going to your server ip addres…

Implementing Client Side WebRTC using Sipml5 javascript

Step 1:

Download and require Sipml5 library function.

Step 2:

Initialize sipml5 Engine in your web page :

var readyCallback = function(e) {
// function called when sipml is successfully initialised.
createSipStack(); // calling this function to create sip stack(see below)
};

var errorCallback = function(e) {
// function called when error occured during sipml initialisation.
};

SIPml.init(readyCallback, errorCallback);

Step 3:

Create Sip Stack :-
Sip Stack is an object that must be created before making/receiving call and sms. Creating Sip stack is an asynchronous process, so you need to create an event listener function to get state change notification.

var sipStack;

function EventListener(e) {

/*
* e.type ;type of event listener
* e.session ; current event session
* e.getSipResponseCode() ; event response code
* e.description ; event description
*/

if(e.type == 'started'){
// successfully started the stack.
register();
} else if(e.type == 'i_new_call'){
// when new incoming call comes.
      …

Multiple file upload using ajax with progress bar

Uploading multiple files using ajax makes a pleasant feeling to the user. It makes even more happier if upload progress status is printed with percentage.

            In this blog, you will make a file upload form using ajax with file upload progress bar.

Prerequisites :

1) Javascript supported browser
2) LAMP Server / XAMPP Server

Code :

index.html

<!DOCTYPE html>

<html>

<head>

    <title>Multiple File Upload using Ajax</title>

    <link rel="stylesheet" type="text/css" href="style.css">

    <script src="//code.jquery.com/jquery-1.10.2.min.js"></script>

</head>

<body>

    <div>

        <form action="action.php" method="post" enctype="multipart/form-data" id="multiple-upload-form">

            <input type="button" id="select-file-btn" value="Select Files" onclick="document.getElementById(…