2016年11月23日 星期三

使用 Yotubue 進行影像串流直播

本篇記錄透過 youtube 進行影像串流直播的過程。

1. 下載 wirecast go app


2. 選擇錄影鍵,此時會要求你登入 youtube帳號,



3. 下圖中選擇 "Albert Liao 即時串流",接著會再回到步驟一的畫面,按下錄影便開始直播了。

4. 接著會回到 step 2的畫面,此時按下紅色錄影鍵便開始直播了。
5. 使用瀏覽器打開Youtube 網頁,選擇 [即時串流] -> [立即直播]就可以看到直播的畫面了。




Wirecast 挺容易使用,但是延遲約 6~8 秒,是真的有點慢,並且其他功能都要付費。也許付費之後,影像延遲會較少。

2016年11月9日 星期三

epoll 介紹

最近把 C10K 問題重新溫習一遍,針對裡面提到的幾個技術,有些時間好好看一下。第一個注意到的就是 linux 系統下的 epoll。

epoll 與 select 的差異

  • select() 有個問題,其最大個數限制 FD_SETSIZE,預設值可能是 1024 或 2048
  • epoll 上限是系統最大可以打開文件的數目,執行 "cat /proc/sys/fs/file-max" 可檢視此上限值。在 Linux 2.6.28之後,要檢視 /proc/sys/fs/epoll/max_user_watches 
  • 另外 epoll 透用 mmap 讓 kernel space 與 user space 共享同一塊內存,減少內存拷貝。而 select() 則需要較多的內存拷貝。

epoll 支援兩種工作模式
LT(level triggered)
支援 block 和 no-block socket,在事件狀態未變更前將不斷被觸發。(直到緩衝區資料全部被讀取)
ET(edge-triggered)
僅支援 no-block socket,在事件狀態改變時只觸發一次。

三個API
int epoll_create(int maxfds);
建立 epoll 文件描述符 
int epoll_ctl (int epfd, int op, int fd, struct epoll_event *event);
增刪或修改文件描述符,這些描述符的集合又稱為 epoll set。
op 可以是 EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD 
epoll_event 結構如下:
struct epoll_event
{
  uint32_t events; /* Epoll events */
  epoll_data_t data; /* User data variable */
}; 
新增 event 時要設定事件以及文件描述符,如下: 
setnonblocking(fd);
ev.events=EPOLLIN|EPOLLET;
ev.data.fd=fd; 
// EPOLLET:工作模式設定為 edge-triggered,若不設定則是 level triggered
// EPOLLONESHOT: 一個事件發生並且讀取之後,不再監聽此文件描述符
// EPOLLIN是監聽讀的事件,若需要監聽寫的事件,可加入EPOLLOUT
int epoll_wait(int epfd, epoll_event *events, int max events, int timeout)
等待用戶感興趣的 IO事件發生, 若有事件發生會返回事件個數,並將事件放入 events。若要關閉 epoll 文件描述符, 直接使用 close() 即可。

程式範例
epollfd = epoll_create1(0);

event.events = EPOLLIN;
event.data.fd = serverfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, serverfd, &event);

while(true) {
 nfds  = epoll_wait(epollfd, &events, MAXEVENTS, timeout);
 for(i = 0; i < nfds; ++i) {
  if(events[i].data.fd == serverfd) {
   conn_sock = accpet(listen_sock,(struct sockaddr *) &addr, &addrlen);
   setnonblocking(conn_sock);                       
   
   ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = conn_sock;
            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
    perror("epoll_ctl: conn_sock");
    exit(EXIT_FAILURE);
   }
   
  } else {
   do_use_fd(events[n].data.fd);
  }
 }
}


參考資料

iNotify 筆記

iNotify 可用來監控目錄或是檔案變化,包含 read/write/add/delete 等等,Linux 2.6.13 之後導入此機制。可以用來判斷是否有人將惡意軟體下載到某個目錄(例如:mirai),或是與rsync結合,當作 Linux 系統的檔案同步機制。

此篇記錄此函數的使用方法。

iNotify 共提供三個 API
  • int inotify_init(void)
  • int inotify_add_watch(int fd, const char* pathname, int mask)
  • int inotify_rm_watch(int fd, int wd)
inotify_init() 初始化完成後,可得到一個file descriptor。
該descriptor 可經由 read()、select()、epoll來操作,與多數的file descriptor無異,同時支援blocking、non-blocking IO。
當有任何事件觸發時,系統會將事件寫入在 inotify_event 結構中,供使用者存取
struct inotify_event {
int      wd;       /* Watch descriptor */
uint32_t mask;     /* Mask of events */
uint32_t cookie;   /* Unique cookie associating related events */
uint32_t len;      /* Size of name field */
char     name[];   /* Optional null-terminated name */
};

程式範例
#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

int fd, wd, length, i = 0;
char buffer[BUF_LEN];

fd = inotify_init();
wd = inotify_add_watch( fd, "/home/strike", 
      IN_MODIFY | IN_CREATE | IN_DELETE );
length = read( fd, buffer, BUF_LEN );  // blocked before event occurs
while ( i < length ) {
 struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
 if ( event->len ) {
  if ( event->mask & IN_CREATE ) { // created
  }
  else if ( event->mask & IN_DELETE ) { // deleted
  }
  else if ( event->mask & IN_MODIFY ) { // modified
  }
 }
 i += EVENT_SIZE + event->len;
}

inotify_rm_watch( fd, wd );
close( fd );


參考資料:
  1. http://www.ibm.com/developerworks/cn/linux/l-ubuntu-inotify/
  2. http://man7.org/linux/man-pages/man7/inotify.7.html

live555 -- wis-streamer 與 media-server 的抉擇

當我們要實作一個 streaming server 時,該參考哪個範例較適合呢? Live555 提供了許多程式範例,以下將簡介各個測試程式,以了解何時該採用哪個範例。

2016年11月6日 星期日

Mirai程式碼分析

Mirai程式碼分析

Mirai 是一網路殭屍病毒,名稱可能是取自日文「未来」,最近作者Anna-senpai開放原始碼,正好可以一窺殭屍病毒作法。本篇針對其程式流程做一介紹,希望在開發自家產品時,能夠避開這些攻擊方法,避免成為殭屍大軍一員。

2016年10月12日 星期三

[QEMU] 在 Ubuntu 平台執行 ARM 平台的某個執行檔

本篇提供一個簡單的qemu執行範例,可以直接執行嵌入式系統(ARM)的執行檔,並說明如何結合基本的檔案輸入輸出,以及如何使用gdb進行除錯。

安裝 qemu
$ sudo apt-get install qemu-user

2016年10月6日 星期四

[Embedded] 取出背景行程的 STDOUT 訊息

在 linux 系統,若需要觀察系統中某行程的輸出訊息 (stdout, stderr),常見的做法是在執行檔案時直接將輸出導入至某個檔案。如下:
1. 分別導出 stdout 與 stderr
executable_file > stdout.txt 2> stderr.txt
2. 將 stdout 與 stderr 導出至同一檔案
executable > output.txt 2>&1
如果是目前已經在執行的行程,要如何在不重啟的情況之下,將 stdout, stderr 轉導向其他檔案呢?比方說某個正在執行的 CGI 程式,如何知道其輸出訊息?

2016年9月13日 星期二

ONVIF -- Profile C and Profile A

最近 ONVIF發布了 Profile A,看來與 Profile C 是很類似的東西,以Profile C為例,定義了兩種角色,Camera或 NVR 可以扮演 ONVIF Client 的角色來控制門禁系統。

  • ONVIF Device,需支援兩項功能。 
  • provide information regarding the PACS related entities included in the system as well as the status of these entities, including standardized PACS related events. 
  • provides basic door control 
  • ONVIF Client,需支援三項功能。 
  • get information regarding the PACS related entities. 
  • do basic door control. 
  • retrieve and receive standardized PACS related events.

    下面將針對這兩種Profile作一比較。

    Prfoile A 與 Profile C 的相同部分

    1. 若一個設備屬於 Physical Access Control System (PACS) 的一部分,便可宣稱支援 ONVIF Profile C 或 Profile A
    要宣稱支援 ONVIF Profile C,要回應下列 scope
     • onvif://www.onvif.org/Profile/C 
    要宣稱支援 ONVIF Profile A,要回應下列 scope
     • onvif://www.onvif.org/Profile/A

    2. 若要支援 Profile C/A,需遵守下列規定
    • 需遵循 ONVIF Core Specification v2.3 或是更新的規範。
    • 需支援 HTTP digest authentication
    • 需支援 pull points 的方式取得 Event, 並且最少要有兩個 pull points
    • 需支援 GetWsdlUrl

    Prfoile A 與 Profile C 的不同

    1. 應用領域不同
    Profile C 官方定義  
    Device
    provide information regarding the PACS related entities included in the system as well as the status of these entities, including standardized PACS related events. This device also provides basic door control
    Client
    get information regarding the PACS related entities and do basic door control.
    It can also retrieve and receive standardized PACS related events.
    Profile A 官方定義 
    Device
    provide functionality to retrieve information, status and
    events and to configure the PACS related entities such as access rules, credentials and schedules. 
    Client
    provide configurations of access rules,credentials and schedules.
    The client can also retrieve and receive standardized PACS related events.
    2. ProfileA 涵蓋了以下規範
    • ONVIF Network Interface Specification
    • Access Rules Service Specification
    • Credential Service Specification
    • Schedule Service Specification
    個人認知:若只要簡單控制門禁,只要實作Profile C,若需要較複雜的控制邏輯,則需要同時實作Profile C 與 Profile A。

    參考資料:
    1. 2013_12_ONVIF_Profile_C_Specification_v1-0.pdf
    2. ONVIF_Profile_A_Spec_RCv1-1.pdf

    2016年9月12日 星期一

    ONVIF -- media2 簡介

    2016/06 ONVIF 發布 Media2 規格書,我將值得注意的地方作一整理,如下:

    1. VideoEncoderConfiguration 內的 Encoding 已可支援 H265
    原本作法(MEDIA) 直接定義 enum { 'JPEG', 'MPEG4', 'H264' }
    新作法(MEDIA2) 改為採用 IANA 定義的字串,例如: "video/H265",如此支援的媒體類型就更廣了。詳細列表可參考 http://www.iana.org/assignments/media-types/media-types.xhtml
       
    2. GetProfile 修改
    原本作法會回 VideoAnalyticsConfiguration
    新作法只會回 Analytics(只有Token,Name, 沒有 Configuration

    3. Set synchronization point
    可強制 Camera 作出三種行為
    a. 立刻送出 iFrame,
    b. 提供使用者訂閱Event的目前狀態。
    c. 提供 PTZ status

    4. VideoRateControl2 新增 ConstantBitRate
    原本的 RateControl 支援下列三項設定
    • FrameRateLimit
    • EncodingInterval
    • BitrateLimit
    現在新增 ConstantBitRate,如此便能夠與 Camera內部設定有一致的對應關係。

    5. MetadataConfiguration 支援 CompressionType.
    為了節省空間,Camera 回傳的 Metadata 除了原本的 XML 格式,還可使用
    • GZIP 或
    • EXI(Efficient XML Interchange Format)       

    6. 新增 SetVideoSourceMode 與 GetVideoSourceModes
    可用來切換 NTSC/PAL ,或是切換 FOV(4:3/16:9) 。
       
    7. 新增 GetVideoEncoderInstances
    可得知每個 VideoSource 最多可同時支援幾條 live stream.

    8. VideoSourceConfigurationExtension2 支援 LensDescription
    使用者可利用此資訊修正鏡頭失真問題(lens distortion)

    參考資料:

    1. http://www.onvif.org/specs/srv/media/ONVIF-Media2-Service-Spec-v1606.pdf    

    2016年7月20日 星期三

    [Embedded] U-Boot的開機流程


    以 U-Boot source code 為例,整理 embedded system 的開機流程

    1.  開機流程
    CPU上電後,會到固定位置讀取指令並且執行,不同架構其位置不同,比方說 ARM 結構的 CPU 會從位址 0x00000000 開始執行,MIPS結構的 CPU 會從位址 0xBFC00000 開始,。 
    若要手動搞定一個嵌入式系統,首先要作的便是安排系統記憶體的編排方式,透過編寫 linker script,可以控制 CPU 上電後會先開始執行的指令,因而讓開機時便開始執行 U-Boot。 
    以下是一個 linker script 例子,此例中,會將 start.o 擺放在 0x00000000 的位置。系統開機時便會在從此處開始取出指令開始執行。一般作法在 start.o 會做些硬體的初始化,然後再執行 u-boot.  (此例子取自 u-boot-2013.04-rc1.tar.bz2 ,參考\board\samsung\smdk6400\u-boot-nand.ld)

    2.  U-Boot 有兩種工作模式
    (1)啟動載入(Boot loading)模式。
    上電後,Bootloader 從板子上的某個固態存放裝置上將作業系統載入到RAM中運行
    (2)下載(Downloading)模式。
    在這種模式下,開發人員可以使用各種命令,(xmodem, tftp, usb and etc...)通過串口連接或網路連接等通信手段從主機(Host)下載檔案(比如內核映射、檔案系統映射),將它們直接放在記憶體運行或是燒入Flash類固態存放裝置中。

    3. U-Boot啟動過程分為兩個階段
    a. Phase 1,
    硬體設備初始化, 準備 RAM 空間(對DDR晶片初始化), 設置 CPU 工作模式為管理模式(SVC)複製 U-Boot程式至 RAM, 啟動 MMU, 設置堆疊,  跳轉到 phase2的程式碼進入點. 
    b. Phase 2,
    初始化要使用的硬體設備, 檢測系統記憶體映象 (memory map), 指定初始化函數清單(如:cpu_init, interrupt_init),為核心設定啟動參數, 進入 U-Boot 命令列 (無窮迴圈)

    4.從 U-Boot 程式碼分析其流程

    start.s (程式碼及註解請看這裡)
    禁止 FIQ, IRQ中斷,並將 ARM CPU 設定為 SVC(Supervisor Calls) 模式 
    設定 Cache和 MMU
    若是從 nand boot,則應該已經做了硬體的Reset,因此不需清除Cache與暫停MMU。否則要 
    • 設定 Cache,此時應該先讓 ICache, DCache, TLB 都失效。
    • 設定 MMU,包含 Endian, Address Align Check, 並通知 MMU 不要使用 ICache, DCache。
    • 設定CPU內的記憶體 TCM(Tightly-coupled memory),此部分也是可分為 Instruction TCM, Data TCM
    設定週邊設備(peripheral)對應的記憶體位址 
    執行 lowlevel_init()
    此函數用來初始化板子相關設定,程式碼會放在 board 目錄下,例如:board/samsung/smdk6400/lowlevel_init.s,此函數會設定LED,WatchDog,Interrupt,System Clock,Serial Port,NAND Flash,DRAM。建置一個小的 Stack,清除BSS段。 
    執行 _main() 
    此函數用來建立C語言的執行環境,執行結束之後會返回 start.s。實作可參考 crt0.s。
    relocate code
    將 ELF 對應的各個區塊,複製到記憶體內。然後啟動MMU,致能TLB。此時還不需要 ICache, DCache,因此不用變更設定。 
    最後設定 exception handler,處理異常事件

    crt0.s (C-runtime startup Code,編譯成 Thumb code),程式碼位置在 arch/arm/lib/crt0.s,主要動作如下
    配置一小塊堆疊,用來放置 160bytes 的 Global Data,將此記憶體位置紀錄在 r8,供後續使用。 
    呼叫 board_init_f(ulong bootflag),此函數是U-Boot執行的第一個 C 函數,程式碼在arch\arm\lib\board.c,此函數會清空 Global Data,將 init_sequence[] 內定義的所有函數都執行一遍,其初始化工作可能包含 serial, baudrate, consol, system information, i2c 跟 dram,並規劃SDRAM空間配置,由位址最大處往前,分別分配 TLB, .Bss, .Data, .Text等區段,接著再分配 malloc空間,global data, abort_stack。

    如果是 non-SPL build,會繼續下列流程
    呼叫 relocate_code(addr_sp, gd, addr_moni),跳回到 start.S中,此時會將 u-boot 程式碼複製到 SDRAM中。複製成功後,執行 bx lr,跳回 crt0.S。 
    呼叫 c_runtime_cpu_setup,此時一樣會跳至 start.S,然後立刻透過 bx lr 返回 crt0.S。 
    清空BSS,控制LED閃爍。
    呼叫 board_init_r(gd_t *id, ulong dest_addr),此函數是 U-Boot 執行的第二個 C函數,也是做些初始化動作,注意的是許多外接設備都在此時才初始化,如 :Ethernet, I2Cfast, LCD, KEYBOARD, USB, SCSI, KGDB等, 最後會進入一個無窮迴圈裡,持續的執行 main_loop(), 
    main_loop()的主要作用就是 U-Boot 啟動管理,此時可能會 delay 數秒 (CONFIG_BOOTDELAY),等待使用者輸入指令。main_loop()的實作可參考 common/main.c。此函數會取得環境參數中的 bootcmd,執行 bootcmd 載入linux kernel,後續任務便由 kernel 接手。 
    可透過 bootm 命令載入 kernel,例如:"bootm 0x80700000"。
    cmd_bootm.c
    設定 kernel 的 entry point 
    取出 zImage 所儲存的 64 bytes header,判斷 magic number是否正確? 
    設定 ramdisk 
    取得 fdt (flattened device tree),設定各項周邊設備。 
    執行 kernel,函數宣告為 void (*theKernel) (int, char **, char **, int *);,此函數內容還需要再研究。

    以ARM開機為例,做個簡單總結,CPU開機時會取出 0x00000000 處的程式碼 (start.s),初始化相關設備,並準備好C語言執行環境,將 u-boot 程式 relocate 至 SDRAM,執行 u-boot 程式,初始化所有設備,最後由 u-boot 傳入各項參數,啟動 kernel。

    2016年6月18日 星期六

    [Study] SCRUM 用一半的時間,做兩倍的事

    『反應速度最快的人就能存活』,本書作者Jeff SUTHERLAND所給出的建議,我會在心裡好好的記住這句話。

    2016年6月8日 星期三

    好碼共享

    這裡會收集一些實用的程式寫法。

    1. hex2bin: 將字串 "F9" 轉成數值 0xF9 (取自 rtmpdump)
    #define HEX2BIN(a)      (((a)&0x40) ? ((a)&0xf) + 9:  ((a)&0xf)) //這個轉換方式超棒
    int hex2bin(char *str, char **hex)
    {
      char *ptr;
      int i, l = strlen(str);
      if (l & 1)
      return 0;
      *hex = malloc(l/2);
      ptr = *hex;
      if (!ptr)
        return 0;
      for (i=0; i    *ptr++ = (HEX2BIN(str[i]) << 4) | HEX2BIN(str[i+1]);
      return l/2;
    }

    2. linker script 內的 ALIGN 作法
    #define ALIGN(exp)   (. + exp - 1) & ~(exp - 1)
    // Return the result of the current location counter (.) aligned to the next exp boundary. exp must be an expression whose value is a power of two. 
    3. linux kernel.h 內的幾個 Macro
    #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
    #define container_of(ptr, type, member) ({    \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetof(type,member) );})
    #define min(x, y) ({    \
    typeof(x) _min1 = (x);    \
    typeof(y) _min2 = (y);    \
    (void) (&_min1 == &_min2);    \ /* type check*/
    _min1 < _min2 ? _min1 : _min2; }) 
    此處可參考 http://stackoverflow.com/questions/5595593/min-macro-in-kernel-h

    4. 建議配置記憶體的方法 p = kmalloc(sizeof(*p), ...); ,此作法好處是好處是萬一pointer p的型別改變時,不會因為忘記同步更該型別的名稱而出錯。

    5. TBD

    2016年6月6日 星期一

    RTMP Spec 心得整理

    本篇是讀完RTMP Specification 1.0 後的心得整理。會以 spec為主並搭配 wireshark  rtmp_sample 封包為例,介紹一個基本的 RTMP 播放流程。

    2016年6月3日 星期五

    [Embedded] 檢視 message queue 資訊

    Linux 下的 IPC 運作若使用 message queue,有兩種 message queue 可用,分別是 SYSTEM V MESSAGE QUEUE 與 POSSIX MESSAGE QUEUE,本篇將介紹如何確認 message queue 中的資訊。

    2016年6月1日 星期三

    使用 wireshark 的 lua script

    Wireshark 支援 lua script ,可以讓我們自行撰寫需要的 disector,簡單的說就是可以讓我自行定義封包要怎麼切割以及顯示。這是個非常有用的功能。

    本次練習的環境為
    • OS X EI  Capitan v10.11.3 64bit
    • wireshark 2.0.2 64bit

    [Study] Google必修的圖表簡報術

    本書作者 Cole Nussbaumer Knaflic 曾任Google人力分析團隊總監,她從心理學的角度介紹設計簡報的一些技巧。推薦大家應該看一下。摘要閱讀心得如下:

    2016年4月10日 星期日

    Online Password Digest of WSS v1.1 Username Token Profile

    The WSS 1.1 Username Token Profile allows digest passwords to be sent in a wsse:UsernameToken of a SOAP message. The formula is
    Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )
    Below list 2 test vector
    Test Vector 1
    Nonce : juVKtZ22NkCZfPadWjVAs2UAAAAAAA==
    created: 2016-03-24T06:16:28.732Z
    password = 1234
    PasswordDigest: oXq1ma7BR1vYdHBW01Hn1Aa1ppQ=
    Test Vector 2
    Nonce : Mdr8Vh3rBzmt1s+3b+nvNJWIlKk=
    created: 2016-03-12T11:54:16Z
    password = 1234
    PasswordDigest: s/bk3KbayLIJb4mK95+g+Feu7+Y=

    You can use this form to check the correctness of your password digest.
    nonce:       
    created:     
    password:
    Reference:
    1. https://docs.oasis-open.org/wss/v1.1/wss-v1.1-spec-os-UsernameTokenProfile.pdf
    2. http://www.esqsoft.com/javascript_examples/date-to-epoch.htm
    3. https://blogs.oracle.com/ashutosh/entry/hash_password_support_and_token

    2016年3月9日 星期三

    iOS - Enable AirPlay for your APP

    之前寫了一個簡單的音樂APP,可以在同時使用 AudioUnit 同時進行錄音與播放。使用手機測試錄音與播放是沒問題的,但是當我想要將程式改為在手機端錄音,透過 AirPlay 在電視上播放時卻發生問題,問題現象是手機上不會出現 AirPlay 選項。

    以下記錄使用 Audio Unit 各種實驗與其結果:

    1. 先了解 Audio 運作時可以設定的各種模式
    摘錄 Apple 定義的 AudioSession Category/Mode 設定值 
    Table B-1  Audio session category behavior
    Category identifiers
    Silenced by the Ring/Silent switch and by screen locking see note
    Interrupts non-mixable apps audio
    Allows audio input (recording) and output (playback)
    AVAudioSessionCategoryAmbient
    Yes
    No
    Output only
    AVAudioSessionCategoryAudioProcessing
    Yes
    No input and no output
    AVAudioSessionCategoryMultiRoute
    No
    Yes
    Input and output
    AVAudioSessionCategoryPlayAndRecord
    No
    Yes by default; no by using override switch
    Input and output
    AVAudioSessionCategoryPlayback
    No
    Yes by default; no by using override switch
    Output only
    AVAudioSessionCategoryRecord
    No (recording continues with the screen locked)
    Yes
    Input only
    AVAudioSessionCategorySoloAmbient
    Yes
    Yes
    Output only
    Table B-2  Modes and associated categories
    Mode identifiers
    Compatible categories
    AVAudioSessionModeDefault
    All
    AVAudioSessionModeVoiceChat
    AVAudioSessionCategoryPlayAndRecord
    AVAudioSessionModeGameChat
    AVAudioSessionCategoryPlayAndRecord
    AVAudioSessionModeVideoRecording
    AVAudioSessionCategoryPlayAndRecord
    AVAudioSessionCategoryRecord
    AVAudioSessionModeMoviePlayback
    AVAudioSessionCategoryPlayback
    AVAudioSessionModeMeasurement
    AVAudioSessionCategoryPlayAndRecord
    AVAudioSessionCategoryRecord
    AVAudioSessionCategoryPlayback
    AVAudioSessionModeVideoChat
    AVAudioSessionCategoryPlayAndRecord
    因為此 APP 同時有 Audio In/Audio Out,所以能夠選擇的設定如下
    • AVAudioSessionCategoryMultiRoute
    • AVAudioSessionCategoryPlayAndRecord
    • AVAudioSessionModeDefault
    • AVAudioSessionModeVoiceChat
    • AVAudioSessionModeGameChat
    • AVAudioSessionModeVideoRecording
    • AVAudioSessionModeMeasurement
    • AVAudioSessionModeVideoChat

    2. 測試不同 Audio Session Mode 與 Audio Unit 同時啟用時所造成的影響
    以下僅為個人實驗結果,當 APP 啟動後,若設定為下列 Category/Mode 不會出現 Airplay選項。
    • AVAudioSessionCategoryMultiRoute
    • AVAudioSessionCategoryPlayAndRecord
    • AVAudioSessionModeGameChat
    • AVAudioSessionModeVideoRecording
    • AVAudioSessionModeVoiceChat

    圖例如下:


    當 APP 啟動後,若設定為下列 Category/Mode 可以出現 Airplay選項。
    • AVAudioSessionModeDefault
    • AVAudioSessionModeMeasurement
    • AVAudioSessionModeVideoChat

    此時已經可以正常播放音樂,圖例如下:
     
    但是一旦當APP開始進行錄音時,卻會變成只有 "iPhone" 與 "iPhone擴音"可選
    圖例如下:


    設定方式舉例如下: 
    [[sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker|AVAudioSessionCategoryOptionMixWithOthers error:&setCategoryErr];
    [[AVAudioSession sharedInstance] setCategory: AVAudioSessionModeDefault error:&setCategoryErr]; 
    經過上述實驗,我會懷疑是否使用Audio Unit 進行錄音時,便無法使用Airplay。


    3. 設定 APP Capabilities,設定 Background Modes 支援 Audio and Airplay,如下圖:
    此作法也是沒用。


    結論:本來想作好此功能之後,可以把家裡電視跟舊iPhone結合成卡拉OK,沒想到一直試不出來,只好作罷。如果有好心人試出這個功能,麻煩請教教我啊,謝謝。

    參考資料
    1. Audio Session Categories and Modes
    2. Jawbone/AudioSessionManager 
    3. AudioSessionProgrammingGuide
    4. EnrichYourAppforAirPlay


    [Embedded] how to check heap corruption

    上週的 linux news 提到 iOS 上的一個問題,Analysis of iOS & OS X Vulnerability: CVE-2016-1722,指出了 heap overflow 的問題。這篇新聞提醒了自己,應該要將之前的實戰經驗做一下整理了。本篇會針對如何找到 heap corruption 的方法作一整理。

    2016年2月26日 星期五

    HLS (HTTP Live streams) 介紹

    許多可以在 iPad 上正常播放的影片,並無法直接串流到 AppleTV。為了讓老婆方便看影片,因此便想找個方法讓 影片能夠串流到 AppleTV,因此需要先研究一下 HLS 機制。

    2016年2月17日 星期三

    [Openalpr] How to compile openalpr for Mac?


    I try to compile openalpr on my MacBook Pro. Below is the note.


    0. Test environment
    • OS X EI Capitan (v10.11.2)
    • tesseract v3.0.4
    • openalpr v2.2.0
    • opencv v3.0.0

    1. Download source
    $ git clone https://github.com/openalpr/openalpr.git$ cd openalpr/src
    $ mkdir build
    $ cd build

    $ wget http://www.leptonica.com/source/leptonica-1.73.tar.gz
    $ tar xvf leptonica-1.73.tar.gz
    $ cd leptonica-1.73
    $ ./configure CC=/usr/bin/clang
    $ make
    $ sudo make install 
    $ cd ~/openalpr
    $ git clone https://github.com/tesseract-ocr/tesseract.git tesseract-ocr
    $ cd tesseract-ocr/
    $ git tag -l $ git checkout tags/3.04.00
    $ ./autogen.sh
    $ ./configure CXX=/usr/bin/clang++ --with-extra-includes=/usr/local/include --with-extra-libraries=/usr/local/lib
    $ make
    $ sudo make install

    3. Install OpenCV, I used OpenCV v3.0.0 that I already installed.
    http://albert-oma.blogspot.tw/2015/08/how-to-install-opencv-in-mac-os.html

    4. Install openalpr
    $ cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/usr/local -DCMAKE_INSTALL_SYSCONFDIR:PATH=/etc -DCMAKE_MACOSX_RPATH=true
    $ make
    $ sudo make install

    5. Test
    $ wget http://i.imgur.com/pjukRD0.jpg -O lp.jpg
    $ alpr lp.jpg

    FAQ:
    1. Compile error about "undeclared identifier 'ENTER_KEY_ONE' and 'ENTER_KEY_TWO'"Referece
     https://github.com/openalpr/openalpr/blob/master/src/misc_utilities/classifychars.cpp, you will find these 2 definitions are missing for __APPLE__ platform. So you need just add below 2 lines, and it will pass the compilation.
    const int ENTER_KEY_ONE = 13;
    const int ENTER_KEY_TWO = 10;
    2. How to generate test license plate images?
    method1. download from here.
    method2. use openalpr deamon to capture from a real camera or streaming server.

    2016年2月4日 星期四

    [Openalpr] How to cross compilation openalpr for ARM?

    Recently, I survey the open source of license plate recognition. The project "openalpr" seems a good option. I reference the Compilation-instructions-(Ubuntu-Linux),  and try to run the program on arm based linux. Below is my memo.