Wednesday, May 2, 2018

What is LAME?

Lame is an MPEG Audio Layer 3 encoder (mp3) licensed under GPL.
Kudos to  Mike Cheng who started this development back in 1998.  However, in its current form Mark Taylor is the leader for LAME.
Today LAME is considered as best mp3 encoder at mid-high bit rates and at VBR. There are many projects that use LAME including famous WinAMP, many of the native operating systems.
Source is available for download at http://lame.sourceforge.net/download.php
LAME is only distributed in source code form. Many of the OS are supporting LAME compilation, which includes Windows, DOS, GNU/Linux, MacOS X, *BSD, Solaris, HP-UX, Tru64, Unix, AIX, Irix, NeXTStep, and so on..

to build the source code, one can follow the below

- Download the source and extract and navigate to the folder.
- Execute the below steps

$ ./configure
$ make
$ sudo make install


as part of the ./configure script execution, it creates make file for all of them mainly to notice for libmp3lame for i386, vector, dll, ACM, MacOS X, VS etc.

config.status: creating Makefile
config.status: creating libmp3lame/Makefile
config.status: creating libmp3lame/i386/Makefile
config.status: creating libmp3lame/vector/Makefile
config.status: creating frontend/Makefile
config.status: creating mpglib/Makefile
config.status: creating doc/Makefile
config.status: creating doc/html/Makefile
config.status: creating doc/man/Makefile
config.status: creating include/Makefile
config.status: creating Dll/Makefile
config.status: creating misc/Makefile
config.status: creating dshow/Makefile
config.status: creating ACM/Makefile
config.status: creating ACM/ADbg/Makefile
config.status: creating ACM/ddk/Makefile
config.status: creating ACM/tinyxml/Makefile
config.status: creating lame.spec
config.status: creating mac/Makefile
config.status: creating macosx/Makefile
config.status: creating macosx/English.lproj/Makefile
config.status: creating macosx/LAME.xcodeproj/Makefile
config.status: creating vc_solution/Makefile
config.status: creating config.h
config.status: executing depfiles commands
config.status: executing libtool commands
The source in zip form is only 1.3 Mb.

But make command resulted in below error

single_module -Wl,-exported_symbols_list,.libs/libmp3lame-symbols.expsym
Undefined symbols for architecture x86_64:
  "_lame_init_old", referenced from:
     -exported_symbol[s_list] command line option
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [libmp3lame.la] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

Tried to compile using Xcode, but that was giving config.h is not found.
Gave the correct path reference to config.h and the error becomes similar to the terminal compilation, below

Undefined symbols for architecture x86_64:
  "_init_xrpow_core_sse", referenced from:
      _init_xrpow_core_init in quantize.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

so, the issue is in linking phase. The compilation is all good.

Looked at the ld command options, which displayed like this below. So all of the architectures are supported.

 ld -v
@(#)PROGRAM:ld  PROJECT:ld64-305
configured to support archs: armv6 armv7 armv7s arm64 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em (tvOS)
LTO support using: LLVM version 9.0.0, (clang-900.0.39.2) (static support for 21, runtime is 21)
TAPI support using: Apple TAPI version 900.0.15 (tapi-900.0.1

Now tried to comment the below lines and apparently that makes a successful build.

//#if defined(HAVE_XMMINTRIN_H)
//    if (gfc->CPU_features.SSE)
//        gfc->init_xrpow_core = init_xrpow_core_sse;
//#endif
//#ifndef HAVE_NASM
//#ifdef MIN_ARCH_SSE
//    gfc->init_xrpow_core = init_xrpow_core_sse;
//#endif
//#endif

So, the problem is really init_xrpow_core_sse. Then I stumbled upon the last link in this and this guy has also mentioned the same and mentions it to be due to the --host parameter.

Darwin myssytemcreds 17.2.0 Darwin Kernel Version 17.2.0: Fri Sep 29 18:27:05 PDT 2017; root:xnu-4570.20.62~3/RELEASE_X86_64 x86_64

from the makefile, it looked like below

host = x86_64-apple-darwin17.2.0
host_alias =
host_cpu = x86_64
host_os = darwin17.2.0
host_vendor = apple



references:
http://lame.sourceforge.net/index.php
https://gist.github.com/trevorsheridan/1948448
https://stackoverflow.com/questions/21255976/how-to-solve-undefined-symbol-init-xrpow-core-sse-when-linking-lame-mp3-encode

Tuesday, May 1, 2018

What is PM2 ? - Some quick learning notes

From the definition from the official site, it appeared like below.

PM2 empowers your process management workflow. It allows you to fine-tune the behavior, options, environment variables, logs files of each application via a process file. It’s particularly useful for micro-service based applications.

Configuration format supported are Javascript, JSON and YAML.

what mattered to me most as part of learning is

- Ability to keep the code running even if it crashes out due to some reason
- Ability to get the log files

Basic usage is :
pm2 start app.js
To install, follow the below
npm install pm2@latest -g

It seems we can create a configuration file to manage multiple applications. Like below

process.yml

apps:
  - script   : app.js
    instances: 4
    exec_mode: cluster
  - script : worker.js
    watch  : true
    env    :
      NODE_ENV: development
    env_production:
      NODE_ENV: production


pm2 start process.yml
Next much useful thing about the PM2 was it as Process Management tool.

PM2 manages application states so that it can start, stop, restart and delete processes.
Some useful commands are :

pm2 start app.js --name "my-api"
pm2 start web.js --name "web-interface"
pm2 restart web-interface
pm2 stop web-interface

to list all running processes pm2 list
pm2 show 0
pm2 list --sort name:desc
pm2 list --sort [name|id|pid|memory|cpu|status|uptime][:asc|desc]

PM2 allows to restart an application based on a memory limit.
pm2 start big-array.js --max-memory-restart 20M

Other interesting thing about the PM2 was the folder structure especially to redirect the application logs to the file. Below are the directory structure

$HOME/.pm2 will contain all PM2 related files
$HOME/.pm2/logs will contain all applications logs
$HOME/.pm2/pids will contain all applications pids
$HOME/.pm2/pm2.log PM2 logs
$HOME/.pm2/pm2.pid PM2 pid
$HOME/.pm2/rpc.sock Socket file for remote commands
$HOME/.pm2/pub.sock Socket file for publishable events
$HOME/.pm2/conf.js PM2 Configuration


references:
http://pm2.keymetrics.io/docs/usage/quick-start/
http://pm2.keymetrics.io/docs/usage/process-management/#max-memory-restart

Monday, April 30, 2018

What is IR.94 VoIP Telephony.

IR.94 is the definition of an IMS profile by listing a number of Evolved Universal Terrestrial Radio Access Network (E-UTRAN), Evolved Packet Core, IMS core and UE Features which are considered essential to launch interoperable IMS based conversational video services.

As per the specification, the service can be offered over LTE or HSPA radio or both.

How does it affect a non IR.94 phone with another VoIP phone with respect to below points from the specification? Yet to figure out.

1. The UE shall indicate the capability to handle video by including a “video” media feature tag in the Contact header of any 18x or 200 response to an INVITE request independent of if video media is part of the SDP answer or not.

==> Most of the INVITEs i have seen, does not include the video feature tag in the Contact header.

2. Video Codecs:

Below are the recommendations from 3GPP. What if these are not supported by the UE? respond back with 0 port for video media in SDP?

Support of ITU-T Recommendation H.264 Constrained Baseline Profile (CBP) Level 1.2 as
specified in 3GPP release 10 TS 26.114 section 5.2.2, is mandatory in the UE and the
entities in the IMS core network that terminate the user plane.
Support for H.265 (HEVC) Main Profile, Main Tier, Level 3.1 as specified in 3GPP release 12
TS 26.114 section 5.2.2 is recommended in the UE and the entities in the IMS core network
that terminate the user plane.
The support in the UE of ITU-T Recommendation H.263 Profile 0 Level 45 as specified in
3GPP release 8 TS 26.114, section 5.2.2, is not required

The pdf in the below reference is having precise information about the profile. A Good read when get some time!

references:
https://www.gsma.com/newsroom/wp-content/uploads//IR.94-v10.0.pdf

Sunday, April 29, 2018

H264/AVC What is SPS and PPS?

SPS and PPS both contains information than an H.264 decoder needs to decode the video data, for e.g. the resolution and frame rate of a video.

for video codecs,
PPS = Picture Parameter Set(PPS contains data common for entire picture)
SPS = Sequence Parameter set (SPS contains data common to SOP, sequence of pictures )

When picture is partitioned into multiple multiple slices say for e.g. for the purposes of transmitting over RTP, likely that it loses the Sequence header and Picture header. A first frame of the picture packet not only contains the picture data, but also some of the important information about the picture header. Loss of this can cause completely incorrectly constructed picture data. So, even if not all packets were lost, if the first packet was lost, almost bad quality picture will be reconstructed or not all reconstructed depending on the implementation.

To circumvent this issue, at the Transport layer a work around was introduced to send the picture header as many as packets. H263 format specified in RFC 2429 specifies this. However, later when H264/AVC was introduced, this issue was considered as an architectural problem in codec itself and SPS and PPS parameter set concept was introduced.

Parameter set can be either part of bitstream or can be received by a decoder through other means such as out of band transmission or hard coding in the decoder.

Note: Sometimes the picture header also contains GOP, Group of picture that contains information whether the previous frames are needed inorder to reconstruct the current frame. I.e. this is an entirely new picture frame mostly. 

references:
https://en.wikipedia.org/wiki/Group_of_pictures
https://cardinalpeak.com/blog/the-h-264-sequence-parameter-set/

Thursday, February 8, 2018

Monday, February 5, 2018

Cloud Functions for Firebase

Cloud functions for firebase allow one to automatically run backend code in response to events triggered by firebase features and HTTPS requests. The code is stored in Google cloud and runs in managed environment. 



The cloud functions that a developer write can respond to events generated by below firebase and Google cloud features



1) Cloud Firestore Triggers

2) Realtime database triggers

3) Firebase authentication triggers 

4) Google analytics for firebase triggers 

5) Crashlytics Triggers 

6) Cloud Storage triggers 

7) Cloud Pub/Sub triggers 

8) HTTP triggers 



How does it work? 



After a function is deployed, Google servers begin to manage functions immediately. listening for events and running the function when it is triggered. As the load increases or decreases, Google responds by rapidly scaling the number of virtual server instances needed to run your function.



LifeCycle of a function 



- The developer writes code for a new function, selecting an event provider (such as Realtime Database), and defining the conditions under which the function should execute.

- The developer deploys the function, and Firebase connects it to the selected event provider.

-  When the event provider generates an event that matches the function's conditions, the code is invoked.

- If the function is busy handling many events, Google creates more instances to handle work faster. If the function is idle, instances are cleaned up.

- When the developer updates the function by deploying updated code, all instances for the old version are cleaned up and replaced by new instances.

- When a developer deletes the function, all instances are cleaned up, and the connection between the function and the event provider is removed.



To enable cloud functions, below is what has to be done: 



- Setup : Install CLI and initialise cloud functions in firebase project

- Write Functions: Write Javascript code (or Typescript ) to handle events from firebase services, Google cloud services, or other event providers. 

- Deploy and monitor : Deploy functions using firebase CLI. 



references:

https://firebase.google.com/docs/functions/

HealthKit introduction iOS

To integrate the HealthKit, first step is to enable HealthKit in the app. This can be done via the Capabilities tab
Second main step is to get the permission to access the HealthKit 

healthManager.authorizeHealthKit { (authorized,  error) -> Void in
    if authorized {
        
        // Get and set the user's height.
        self.setHeight()
    } else {
        if error != nil {
            print(error)
        }
        print("Permission denied.")
    }
}

We need to request authorisation to share the type of data. 

let healthKitStore: HKHealthStore = HKHealthStore()
    
    func authorizeHealthKit(completion: ((success: Bool, error: NSError!) -> Void)!) {
        
        // State the health data type(s) we want to read from HealthKit.
        let healthDataToRead = Set(arrayLiteral: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)!)
        
        // State the health data type(s) we want to write from HealthKit.
        let healthDataToWrite = Set(arrayLiteral: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)!)
        
        // Just in case OneHourWalker makes its way to an iPad...
        if !HKHealthStore.isHealthDataAvailable() {
            print("Can't access HealthKit.")
        }
        
        // Request authorization to read and/or write the specific data.
        healthKitStore.requestAuthorizationToShareTypes(healthDataToWrite, readTypes: healthDataToRead) { (success, error) -> Void in
            if( completion != nil ) {
                completion(success:success, error:error)
            }
        }
    }

Below is a sample that reads height data from the healthKit 

    func getHeight(sampleType: HKSampleType , completion: ((HKSample!, NSError!) -> Void)!) {
        
        // Predicate for the height query
        let distantPastHeight = NSDate.distantPast() as NSDate
        let currentDate = NSDate()
        let lastHeightPredicate = HKQuery.predicateForSamplesWithStartDate(distantPastHeight, endDate: currentDate, options: .None)
        
        // Get the single most recent height
        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
        
        // Query HealthKit for the last Height entry.
        let heightQuery = HKSampleQuery(sampleType: sampleType, predicate: lastHeightPredicate, limit: 1, sortDescriptors: [sortDescriptor]) { (sampleQuery, results, error ) -> Void in
                
                if let queryError = error {
                    completion(nil, queryError)
                    return
                }
                
                // Set the first HKQuantitySample in results as the most recent height.
                let lastHeight = results!.first
            
                if completion != nil {
                    completion(lastHeight, nil)
                }
        }
        
        // Time to execute the query.
        self.healthKitStore.executeQuery(heightQuery)
    }

Now to write the distance value into the HealthKit store, below is what needed 

func saveDistance(distanceRecorded: Double, date: NSDate ) {
                
        // Set the quantity type to the running/walking distance.
        let distanceType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
        
        // Set the unit of measurement to miles.
        let distanceQuantity = HKQuantity(unit: HKUnit.mileUnit(), doubleValue: distanceRecorded)
        
        // Set the official Quantity Sample.
        let distance = HKQuantitySample(type: distanceType!, quantity: distanceQuantity, startDate: date, endDate: date)
        
        // Save the distance quantity sample to the HealthKit Store.
        healthKitStore.saveObject(distance, withCompletion: { (success, error) -> Void in
            if( error != nil ) {
                print(error)
            } else {
                print("The distance has been recorded! Better go check!")
            }
        })
    }


references: