2016년 10월 26일 수요일

Android storage mount configuration

  1. Android storage mount configuration
    1. # cat /init.rc
root@mv7420:/ # cat /init.rc | grep mount
….
   # Create cgroup mount point for cpu accounting
   mount cgroup none /acct cpuacct
….
   # Create cgroup mount point for memory
   mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000
   mount cgroup none /sys/fs/cgroup/memory memory
….
   # Secure container public mount points.
   mount tmpfs tmpfs /mnt/asec mode=0755,gid=1000
….
   # Filesystem image public mount points.
   mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000
….
   # memory control cgroup
   mount cgroup none /dev/memcg memory
….
   # Create cgroup mount points for process groups
   mount cgroup none /dev/cpuctl cpu
….
   # pstore/ramoops previous console log
   mount pstore pstore /sys/fs/pstore
….
  # once everything is setup, no need to modify /
   mount rootfs rootfs / ro remount
   # mount shared so changes propagate into child namespaces
   mount rootfs rootfs / shared rec
….

    1. # cat /init.<device>.rc
root@mv7420:/ # cat init.samsungexynos7420.rc
import init.samsungexynos7420.usb.rc

on init
   start watchdogd

   chmod 0701 /mnt/media_rw
   chown root root /mnt/media_rw
….
….

service setup_fs /system/bin/setup_fs mmcblk0p3  mmcblk0p4
   class core
   user root
   group root
   oneshot

service battery_charger /sbin/healthd -c
       user root
       group root
       class charger
       seclabel u:r:healthd:s0

on fs
   mount_all /fstab.samsungexynos7420
   setprop ro.crypto.fuse_sdcard true

# Boost Block I/O Performance
   write /sys/block/sda/queue/read_ahead_kb 512
   write /sys/block/sda/queue/rq_affinity  2
   write /sys/block/sda/queue/iosched/slice_idle 0

# Permissions for ION
   chmod 0660 /sys/class/ion_cma/ion_video_ext/isolated
   chown system system /sys/class/ion_cma/ion_video_ext/isolated

# Permissions for backlight
   chmod 0660 /sys/class/backlight/pwm-backlight.0/brightness
   chown system system /sys/class/backlight/pwm-backlight.0/brightness

# Copy DRM Key
   copy /system/app/wv.keys /factory/wv.keys


    1. External storage is managed by a combination of the vold init service and MountService system service. Mounting of physical external storage volumes is handled by vold, which performs staging operations to prepare the media before exposing it to apps.
      https://source.android.com/devices/storage/config.html
    2. Android 4.2.2 and earlier : /etc/vold.fstab
    3. Android 4.3 and later : /fstab.<device>
      the raw physical device must first be mounted /devices/xxx, then vold will manage the sdcard0, usb1, usb2
      # cat fstab.samsungexynos7420
# Android fstab file.
#<src>                  <mnt_point>         <type>    <mnt_flags and options>
                           <fs_mgr_flags>
# The filesystem that contains the filesystem checker binary (typically /system) cannot
# specify MF_CHECK, and must come before any filesystems that do specify MF_CHECK

/dev/block/platform/15740000.dwmmc0/by-name/system      /system ext4    rowait
/dev/block/platform/15740000.dwmmc0/by-name/cache       /cache  ext4    noatime, nosuid,nodev,nomblk_io_submit,errors=panic      wait
/dev/block/platform/15740000.dwmmc0/by-name/userdata    /data   ext4    noatime,
nosuid,nodev,nomblk_io_submit,discard,noauto_da_alloc,errors=panic    wait,force encrypt=/cache/metadata

# VOLD
/devices/15560000.dwmmc2/mmc_host/mmc2          auto            vfat    default voldmanaged=sdcard0:auto
/devices/15510000.usb                           auto    vfat    default voldmana ged=usb1:auto
/devices/15400000.usb/15400000.dwc3/xhci-hcd    auto    vfat    default voldmana ged=usb2:auto


  1. MMC device partition name
# ls -l /dev/block/platform/15740000.dwmmc0/by-name/
lrwxrwxrwx root     root              2046-11-08 15:37 fat -> /dev/block/mmcblk0p1
lrwxrwxrwx root     root              2046-11-08 15:37 system -> /dev/block/mmcblk0p2
lrwxrwxrwx root     root              2046-11-08 15:37 userdata -> /dev/block/mmcblk0p3
lrwxrwxrwx root     root              2046-11-08 15:37 cache -> /dev/block/mmcblk0p4
lrwxrwxrwx root     root              2046-11-08 15:37 efs -> /dev/block/mmcblk0p5
lrwxrwxrwx root     root              2046-11-08 15:37 kernel -> /dev/block/mmcblk0p6
lrwxrwxrwx root     root              2046-11-08 15:37 ramdisk -> /dev/block/mmcblk0p7
lrwxrwxrwx root     root              2046-11-08 15:37 recovery -> /dev/block/mmcblk0p8
lrwxrwxrwx root     root              2046-11-08 15:37 dtb -> /dev/block/mmcblk0p9
lrwxrwxrwx root     root              2046-11-08 15:37 ldfw -> /dev/block/mmcblk0p10
lrwxrwxrwx root     root              2046-11-08 15:37 bootlogo -> /dev/block/mmcblk0p11
lrwxrwxrwx root     root              2046-11-08 15:37 font -> /dev/block/mmcblk0p12
lrwxrwxrwx root     root              2046-11-08 15:37 engmode -> /dev/block/mmcblk0p13

  1. MMC device partition blocks
# cat /proc/partitions
major minor  #blocks  name
179        0   30535680 mmcblk0
179        1         32 mmcblk0p1
179        2    2662400 mmcblk0p2
179        3   26941360 mmcblk0p3
179        4     819200 mmcblk0p4
179        5      10240 mmcblk0p5
179        6      20480 mmcblk0p6
179        7      26624 mmcblk0p7
259        0      26624 mmcblk0p8
259        1       1024 mmcblk0p9
259        2       2048 mmcblk0p10
259        3      10240 mmcblk0p11
259        4       1024 mmcblk0p12
259        5       2048 mmcblk0p13
179       24       4096 mmcblk0rpmb
179       16       4096 mmcblk0boot1
179        8       4096 mmcblk0boot0
254        0   26941360 dm-0


  1. for MTD and EMMC devices, the  partition layout and name can be retrieved by reading /proc/mtd, /proc/emmc

2016년 10월 17일 월요일

PJSIP 설치

컴파일

2.      컴파일 환경 설정
1) environment-setup-cortexa5hf-vfp-poky-linux-gnueabi
에서 LD = $CC로 수정
2) source /home/albert/Workspace2/VoIP/yocto_gcc/environment-setup-cortexa5hf-vfp-poky-linux-gnueabi (
sama5d31ek_build 문서참조)
3) make distclean &&  make clean
4) ./configure --host=arm-linux
5) pjlib/include/pj/config_site.h
에서 PJ_DEBUG 1, PJ_LOG_MAX_LEVEL 4 로 수정
6) make dep && make

3.      Alsa 라이브러리 설치
rootfs에 라이브러리가 없을 경우 필요한 작업이다.
1) cp –r poky/build-atmel/tmp/sysroots/sama5d3xek/usr/include/alsa  ~/yocto_sdk/sysroots/cortexa5hf-vfp-poky-linux-gnueabi/usr/include;
2) cp poky/build-atmel/tmp /sysroots/sama5d3xek/usr/lib/libasound.so*  ~/yocto_sdk/sysroots/cortexa5hf-vfp-poky-linux-gnueabi/usr/lib

4.      시스템 설정
A.     소켓버퍼 최대 사이즈를 늘린다. 아래처럼 명령을 이용하거나 etc/sysctl.conf에 설정한다. (“net.core.rmem_max=26214400” 형식으로 설정)
                                   i.         $ sysctl -w net.core.rmem_max=26214400
$ sysctl -w net.core.wmem_max=26214400

5.      테스트
pjlib-test: PJLIB 기능테스트, pjlib/bin/pjlib-test-*
pjsip-test: PJSIP
SIP 기능테스트, pjsip/bin/pjsip-test*
pjsystest:
오디오 기능테스트, pjsip-apps/bin/pjsystest-*

 pjsua application on pjsip-apps/bin directory. PJSUA manual can be found in http://www.pjsip.org/pjsua.htm page.

컴파일시 발생 문제해결

문제:
../src/pjmedia-audiodev/alsa_dev.c:37:28: fatal error: alsa/asoundlib.h: No such file or directory
해결: alsa 라이브러리 헤더 추가
cp –r poky/build-atmel/tmp/sysroots/sama5d3xek/usr/include/alsa  ~/yocto_sdk/sysroots/cortexa5hf-vfp-poky-linux-gnueabi/usr/include

문제:
/src/pjmedia-audiodev/alsa_dev.c:317: undefined reference to `snd_lib_error_set_handler'
해결링크옵션에 alsa 라이브러리 추가
cp -l r poky/build-atmel/tmp /sysroots/sama5d3xek/usr/lib/libasound.so*  ~/yocto_sdk/sysroots/cortexa5hf-vfp-poky-linux-gnueabi/usr/lib/

문제:
sphinx-build -b html -d _build/doctrees   . _build/html
make: sphinx-build: Command not found
make: *** [html] Error 127




해결: apt-file 을 설치해서 sphix-build가 어떤 패키지에 있는지 검색 후 설치한다.
1.      sudo apt-get install apt-file
2.      apt-file search sphinx-build
3.      sudo apt-get install python-sphinx

문제: 컴파일 후 타겟에서 실행하면 실행안됨
root@sama5d3xek:/mnt# ls -al pjsip-apps-bin/pjsua-arm-unknown-linux-gnu
-rwxrwxr-x 1 1000 1000 6015936 May 18  2016 pjsip-apps-bin/pjsua-arm-unknown-linux-gnu
root@sama5d3xek:/mnt# ./pjsip-apps-bin/pjsua-arm-unknown-linux-gnu
-sh: ./pjsip-apps-bin/pjsua-arm-unknown-linux-gnu: No such file or directory
해결: source /yocto_sdk/environment-setup-cortexa5hf-vfp-poky-linux-gnueabi 에서
LD = $CC 로 수정한다. 추가로 필요한 링커 옵션은 –Wl 으로 넘긴다.
arm-poky-linux-gnueabi-ld 로 링킹할 경우 스텁코드링킹이 정상적으로 바인딩되지 않는 것 같다.

설정파일

예시1(using-opensip proxy)

--id sip:atmel@192.168.1.220
--registrar sip:192.168.1.220
--proxy sip:192.168.1.220;lr
--realm *
--username atmel
--password atmel
--play-file TheCubanMissileCrisis_8K.wav
--rec-file rec.wav
--add-buddy sip:cisco@192.168.1.220
--add-buddy sip:windows@192.168.1.220
--add-buddy sip:android@192.168.1.220
--auto-answer 200
--log-file log_file.txt
--log-level 4
--app-log-level 4
--ec-tail=400
--ec-opt=1


기능테스트

pjlib-test

- 모든 테스트 성공.

loopbask mic to speaker

 - pjsua: >>>> cc 0 0
 - 노이즈 없이 깨끗하게 잘 들림.

pjsip-test

x86테스트
- x86에 같은버젼의 alsa pjsip를 설치후 pjsip-test를 돌리면 모든 테스트 성공.(26분소요)
10:20:18 ./pjsip/bin/pjsip-test-x86_64-unknown-linux-gnu
(….)
10:46:55.616 Peak memory size=4154504685 MB
10:46:55.621 10:46:55.621 Stack max usage: 0, deepest: :0
10:46:55.621 Looks like everything is okay!..

Running tsx_uas_test(loop-dgram) 실패 : test10
문제:
tsx_uas_tes 10 timeout 실패
해결: 소켓 버퍼의 최대사이즈를 늘린다.
- receive buffer = rmem, send buffer = wmem
$ sysctl -w net.core.rmem_max=26214400
$ sysctl -w net.core.wmem_max=26214400

pjsua

전화걸기:
./pjsua sip:192.168.1.64

전화받기:
>>> a
>>> 200

자동응답:
$ pjsua --play-file /path/PROMPT.WAV --auto-answer 200 --auto-play --auto-loop

RTP 송수신 퍼포먼스 테스트

pc-server: /pjsip-apps/bin/samples/…/streamutil --send-recv --play-file=test.wav --remote=192.168.1.10:4000
target-client: /pjsip-apps/bin/samples/…/streamutil --send-recv --play-file=test.wav --remote=192.168.1.212:4000



2016년 10월 7일 금요일

PJSIP Media 흐름의 이해


이 문서는 https://trac.pjsip.org/repos/wiki/media-flow를 번역한 것입니다.
2016년 10월 7일  신C




1.Media Interconnection

위 다이어그램의 주요 빌딩블럭은 아래 구성요소로 이루어져 있다.


2. Setting up Media Interconnection

미디어의 상호작용은 아래 순서로 설정된다.
  1. 어플리케이션 초기화시 어플리케이션은 Sound Device Port와 Conference Bridge를 생성한다. 이 두 오브젝트는 일반적으로 어플리케이션의 생명주기와 같이한다.
  2. 전화걸기나 전화수신을 위한 설정을 할때, 어플리 케이션은 media transport instance를 만든다.(일반적으로 UDP Media transport). 이 media transport를 통해 어플리케이션은 INVITE session에 들어가는 local SDP에 전송주소와 포트를 설정한다.
  3. 통화에서 offer/answer session 이 만들어 지면(그리고 on_media_update() 콜백인 호출되고), 어플리케이션은 INVITE session에 들어있는 local와 remote SDP를 이용하여 Media session Info를 생성한다.
  4. 어플리케이션은 Media session Info로 부터 Media session을 만든다. 이 오브젝트는 이전에 만든 Media Transport를 지정한다. 이 과정에서 코덱 세팅과 Media Session Info의 파라미터를 통해 Media Stream들을 만들고 Media Stream과  Media Trasport를 연결한다.
  5. 어플리케이션이 Media session으로 부터 Media Audio Stream을 가져와 이 스트림을 conference bridge에 등록한다.
  6. 어플리케이션은 bridge의 Media Stream slot을 slot Zero와 같은 다른 슬롯에 연결한다. slot zero는 일반적으로 sound device에 연결된다.
    소스- media state가 변경되면 on_call_media_state() 콜백함수가 호출된다. 이 함수는 연결된 음성을 sound device, file 또는 loop로 연결해 준다.
    pjsua_app.c : on_call_media_state() -> on_call_audio_state()  
    > call_conf_slot = pjsua_call_info->media[media_index].stream.aud.conf_slot;
    > pjsua_conf_connect(call_conf_slot, 0) :스피커,
    >> pjsua_conf_connect(0, call_conf_slot) : 마이크
    >> pjmedia_conf_connect_port()
      > src_port->listener_slots[src_port->listener_cnt] = sink_slot;
    Conference Bridge에서 소스포트의 listener_slots 를 참조하여 sink_slot에 음성을 전달한다.


3.Media Timing

모든 미디어 플로우는 sound device의 타이밍에 따르게 된다. 특히 playback 콜백이 그렇다.


3.1 The Main Flow(Playback callback)

  1. sound device가 스피커로 재생할 프레임이 추가로 필요하면, sound device abstraction은 play_cb() 콜백을 호출할 것이다. 이 함수는 sound device가 생성될 때 등록된다.
  2. sound device는 play_cb() 콜백을 downstream port의 pjmedia_port_get_frame() 호출로 전환한다. 이런 상황은 Conference Bridge 에서 발생한다.
  3. conference bridge으로 pjmedia_port_get_frame()의 호출은 conference bridge내 모든포트를 위해 다른 pjmedia_port_get_frame 호출을 야기한다. 필요에 따라 신호를 섞어 주고 pjmedia_port_put_frame()을 한번더 호출하므로 섞인 신호를 전달한다. bridge가 이 모든 것을 처리한 후, 섞인 신호는 slot zero를 위해 원래의 pjmedia_port_get_frame() 호출으로 반환된다. 그리고 반환된 신호는 sound device에 전달된다.
  4. conference bridge에 의한 media stream port의 pjmedia_port_get_frame() 호출은  jitter buffer로 부터 하나의 프레임을 가져오도록 만든다. 그리고  설정된 코덱을 이용해 디코딩한다. 이 후 PCM 프레임을 호출한 함수에 리턴 한다. jitter buffer는 다른 흐름에서 채워지는 것을 주의하라.(네트워크 소켓의 poll 에서 채워짐)
  5. conference bridge에 의한 media stream port의 pjmedia_port_put_frame() 호출은 스트림에 설정된 코덱으로 인코딩하도록 만든다. 그리고 RTP 패킷으로 만든다.RTCP 세션을 업데이트하고 RTCP 전송을 조정한다. RTP/RTCP 패킷은 media_trasport로 전달되고 media_trasport는 이 패킷을 네트워크로 전송한다.


3.2 Recording Callback

위 흐름은 스피커를 쪽의 특정 방향에 대해서만 기술했다. 마이크로부터 나오는 흐름은 어떨까?
  1. 마이크로 부터 오디오 프레임 하나를 캡춰하면 rec_cb() 콜백을 호출하여 이를 알린다. 이 콜백함수는 sound device가 생성될 때 등록된다.
  2. sound device 포트는 rec_cb() 콜백을 downstream 포트의 pjmedia_port_put_frame() 으로 전환한다. 이런상황은 Conference Bridge에서 발생한다.
  3. pjmedia_port_put_frame() 함수가 conference bridge에서 호출되면, bridge는 PCM 프레임을 내부 버퍼(프레임 큐)에 저장한다. 저장된 버퍼는 bridge가 모든 포트로부터 프레임을 가져와 믹싱한 후 main 흐름(위 bridge의 pjmedia_port_get_frame  호출)에 전달된다.
잠재적인 문제점:
이상적으로 rec_cb()와 play_cb()는 sound_device에 의해 교대로 호출되어야 한다. 하지만 불행하게도 이것을 항상 보장해주지는 않는다. 많은 저사양 사운드카드는 rec_cb() 콜백을 연속적으로 여러번 호출하고 이후에 play_cb()를 연속적으로 호출하는 것이 일반적이다. 이런 상황을 보완하기 위해, 내부 sound device 큐 버퍼를 8 프레임 정도들어 갈 수 있도록 충분히 크게 만든다. 이 설정은 conference.c 파일의 RX_BUF_COUNT 매크로를 변경할 수 있다. 아~주 안좋은 사운드카드는 8번 이상의 연속적인 rec_cb()/play_cb() 호출을 할 수도 있는데. 이런 경우 RX_BUF_COUNT를 늘려야 한다.


3.3 incoming RTP/RTCP Packets

수신되는 RTP/RTCP 패킷은 위에서 설명한 흐름에 의해 좌우되지 않고 다른 흐름(“thread)에서 의해 전단된다. 바로 소켓 디스크립터를 폴링하는 흐름이다.


PJMEDIA의 UDP Media Transport 에서 RTP와 RTCP 소캣을 IOQueue에 등록한다. 여러개의  media transport 인스턴스는 하나의 IOQueue에 등록되고, ioqueue의 폴링은 모든 media transport에 수신되는 패킷을 체크한다.


어플리케이션은 ioqueue 인스턴스를 어디에 둘지에 따라 다른 전략을 선택할 수 있다.
  • 어플리케이션은 Media Endpoint가 내부 IOQUEUE를 초기화하고 IOQUEUE를 폴링하기 위한 하나 이상의 worker thread를 시작한다. 이 전략은 분리된 스레드에 의해 media 소켓을 폴링하므로 추천방법 중 하나이다. (PJSUA-API의 기본 설정임).
  • 어플리케이션은 SIP와 media 소켓을 위해 하나의 IOQUEUE를 이용할 수 있다. 그리고 하나의 스레드에서 모든 것을 폴링한다. 예를 들면 메인 스레드에서 가능하다. 이 전력을 선택하려면, 어플리케이션은 media endpoint 생성시 사용될 IOQueue 인스턴스를 지정하고 worker thread를 비활성화해야 한다. 이 전략은 스레드 수를 최소로 해야 하는 소규모 시스템에 효율적이다.


수신되는 RTP 패킷의 흐름은 아래와 같다.

  1. Media Endpoint의 내부 worker thread는 모든 media transport가 등록된 IOQueue를 폴링한다.
  2. 패킷이 수신되면, 폴링함수는 UDP media transport의 on_rx_rtp() 콜백함수를 수행한다. 이 콜백함수는 호출전에 UDP media transport 에 의해 ioqueue에 등록되었다.
  3. on_rx_rtp() 콜백함수는 media stream port에 수신된 RTP 패킷을 보고한다. 이 media stream은 어플리케이션이 세션을 초기화 하는동안 UDP media transport에 연결되었다.
  4. media stream은 내부 RTP 세션을 이용해 RTP 패킷을 분해하고, RX 통계를 업데이트한다. 사용된 코덱에 따라 페이로드를 디코딩하고(하나의 패킷에 여러 프레임이 포함될 수도 있다.), jitter buffer에 전달한다.
  5. 수신된 패킷 처리는 여기서 멈춘다. 이후 jitter buffer에 저장된 프레임은 main 흐름(pjmedia_port_get_frame()함수 호출되는 흐름)에 의해 빠져 나가게 된다.