레이블이 Audio인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Audio인 게시물을 표시합니다. 모든 게시물 표시

3/10/2016

DM368-AUDIO 수정사항

1. KERNEL 

DM368 관련 Audio 를 비롯하여, 관련설정 부분을 간단히 요약한다. 
관련 기초내용들은 전부생략한다.

ALSA Flow 간단히 설명 
  https://ahyuo79.blogspot.com/2016/02/audio-alsa-3-kernel-playback-and-capture.html


1.1 KERNEL CONFIG

DM368인 경우, 외부 AUDIO CODEC(ADC,DAC)로 변경을 할 경우, McBSP의 Driver가 변경이 된다.
잘못이해한 부분은 VOICE CODEC (ADC와 DAC를 비롯하여 G.711 , AAC 기능까지 전부 한 HW로 합쳐진줄 오해했다, 그럼 그렇지) 

현재 TI에서 제공하는 VOICE CODEC은 MIC는 MONO 이므로, 이부분은 추후 수정하도록해야함

$ cd ~/dm368/mt5/Source/dvsdk_ipnctools/ipnc_psp_03_21_00_04/kernel
$ vi ./arch/arm/configs/davinci_dm368_ipnc_ubifs_defconfig 

CONFIG_SND_SOC=y
CONFIG_SND_DAVINCI_SOC=y
CONFIG_SND_DAVINCI_SOC_VCIF=y
CONFIG_SND_DAVINCI_SOC_EVM=y
# CONFIG_SND_DM365_AIC3X_CODEC is not set
CONFIG_SND_DM365_VOICE_CODEC=y
CONFIG_SND_SOC_I2C_AND_SPI=y
# CONFIG_SND_SOC_ALL_CODECS is not set
CONFIG_SND_SOC_CQ0093VC=y

// 추가사항 (AIC3100)
    CONFIG_SND_DM365_AIC3X_CODEC,
    CONFIG_SND_DAVINCI_SOC_I2S,
    CONFIG_SND_SOC_TLV320AIC3X
 
// 제거사항 (VOICE CODEC)
     CONFIG_DAVINCI_MCBSP
     CONFIG_SND_DAVINCI_SOC_VCIF
     CONFIG_SND_DM365_VOICE_CODEC
     CONFIG_SND_SOC_CQ0093VC


1.2 AIC3100 driver 수정

DM368에 AIC3x는 Driver는 제공하지만, Register Map 차이가 많이나서 수정함
AIC3100 Driver는 인터넷에 tlv320aic3100.c는 있지만  i2c regmap이 필요
현재 AIC3x에서 수정하고 수정, 추후 시간여유가 있다면, aic3100.c로 수정하고 추가.

$ vi ./arch/arm/mach-davinci/board-dm368-ipnc.c           // Kernle 소스 수정, 61 Reset
                                                                           //I2C Device 등록 AIC3100 

$ vi ./arch/arm/mach-davinci/dm365.c      
$ vi ./arch/arm/mach-davinci/mcbsp.c      MCBSP  //CONFIG_DAVINCI_MCBSP
$ vi ./sound/soc/davinci/davinci-i2s.c       MCBSP  //CONFIG_SND_DAVINCI_SOC_I2S 

$ vi ./sound/soc/davinci/davinci-evm.c    // I2C driver 등록  수정    AUDIO_FORMAT 변경
$ vi ./sound/soc/codecs/tlv320aic3x.c     // AIC3100 변경 


2. APP 관련 수정사항

DM368 IPNC에서 Application에서 Kernel의 Device를 Control하는 Main Application은 AV Server라는 프로그램이다.  
이 APP은 기본적으로 Audio 및 Video , 및 기타기능를 모두 조절하므로, Driver를 Porting 해서 Driver를 검증을 완료하고 문제가 발생했다면, 
그 다음에 봐야 할 부분이, AV Server이므로 Debug를 해야 할 포인트와 관련부분을 기억해야겠다.

관련메뉴얼은 appropho에서 제공을 하고 있다.

2.1 AV SERVER-AUDIO-DEBUG 

$ vi ./av_capture/application/ipnc/av_server/inc/avserver_debug.h
                      //#define AVSERVER_DEBUG_AUDIO_THR  해제 

$ vi ./av_capture/framework/alg/inc/alg_audEncDec.h 
                      // Audio Encode Decode Debug을 담당 AAC와 G.711 
                      //#define ALG_AUD_ENC_DEBUG  해제 
                      //#define ALG_AUD_INP_FILE_DUMP_DEBUG  audioInp.pcm 파일 생성 
                      //#define ALG_AUD_ENC_FILE_DUMP_DEBUG  audioOut.aac 파일 생성 

$ vi ./av_capture/framework/drv/usermod/src/drv_audio.c   
                      // Audio ALSA API Interface 부분 Debuging 
                      //#define DRV_AUDIO_DEBUG 해제하면됨 


2.2 AV SERVER-AUDIO 

각 AV Server Audio 부분을 수정하여 검증 및 테스트를 진행하도록 한다. 

$ vi ./av_capture/application/ipnc/av_server/src/audio/audioThr.c                 
                      // G.711 and AAC   , avserver.h->avserver_debug.h 포함 
                      //#define NUM_CHANNELS      (1->2)   수정 ,     
                      // 위와 같이 수정시 RTSP의 SDP부분 수정요구 Channel? or Mono 녹음

$ vi ./av_capture/framework/drv/usermod/src/drv_audio.c   
                       // ALSA Interface  API open 및 설정 (parameter)
                      - 아래와 같이 Serial에서 Capture debug , Encoding 상태시  
                      # cat /proc/asound/card0/pcm0c/sub0/status 
                      # cat /proc/asound/card0/pcm0c/sub0/sw_params
                      # cat /proc/asound/card0/pcm0c/sub0/hw_params 

$ vi ./av_capture/framework/alg/src/alg_audEnc.c  
                      //  AAC or G.711 설정      ALG_AUD_CODEC_AAC 

  • Motion Detection과 관련부분 
DM368에서 제공하는 Motion Detection 기능이며, 관련 세부사항은 생략 
$ vi ./av_capture/application/ipnc/av_server/src/video/videoMotionThr.c

$ vi ./av_capture/framework/alg/src/alg_motionDetect.c 

$ vi ipnc_app/sys_server/src/proc_alarm.c  
                      //id_motion_sem , Semaphore 1729 initialized.  

$ grep -r DRV_gpioSetMode  
                      // GPIO 관련부분 검색 


  • Audio 부분 수정포인트 
  http://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/100/p/252454/888321
  https://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/100/t/252454


3.  How To TEST 

테스트 방법은 ALSA의 Tools을 이용하여 간단하게 테스트를 진행 

3.1 ALSA AUDIO TEST

초반에 Audio Driver는 수정완료 한 후, 아래와 같이 ALSA에서 제공하는 프로그램으로 TEST

  • 문제점 
현재의 문제점은 Mono로 Capture가 진행하고, Playback을 했을때, 진행이 되어야한다.
하지만 진행이 되지 않는다. 이 부분 추후 진행
**아래의 TEST 하기전에 반드시 av_server를 사전에 차단하고 실행해야함.

 
$ arecord -f S16_LE -r48000 -c 2  -d 10 /root/test.wav     // CAPTURE 

$ aplay  /root/test.wav    //PLAYBACK 

간단하게 PCM S16_LE format으로 Sample rate를 정해서 저장 


3.2  RTSP AUDIO TEST 

RTP로 H.264 or MPEG4를 전송을 한다, 이때, Audio 부분을 포함하기에 이부분을 Web에서 설정만 해주면 제대로 동작을 해야한다.

만약 동작하지 않는다면 AV Server Debug 및 Driver TEST를 다시 진행 

Web->Audio->Enable Audio 설정 및  AAC-LC로 변경, 모드, Samplerate 및 Bitrate 변경.

Live Video 에서 Audio 체크 후 확인 or VLC에서 rtsp로 확인


4. 문제점 
                                     
현재 Codec Driver 문제로 인하여, av server의 오 동작이 발생하며, 추후 시간이 있다면,이 부분을 수정한다.  
이 부분은 데모수준으로 끝내며, 현재 내일이 아니므로 추후에 다시 보도록하자 

2/26/2016

Audio-ALSA Playback & Capture Flow

1. ALSA의 기본 API  

DM368은 TI에서 제공하는 Audio Guide는 없지만 구조는 거의 동일하다.
TI 제공하는 Audio는  기본 구조는 동일하지만, CPU에따라 EVM에 따라 조금씩 다르다.
하지만, OMAP인 경우 기본구조와 다르게 Audio 구조가 복잡하지만, 요즘은 거의 다 ALSA로 기반으로 하므로 아래와 같이 ALSA의 API들을 알아두록하자. 

  • Audio 관련 부분 전체 Index
TI에서 제공해주는 Audio 관련 ALSA Guide로 현재 AM38xxx 와 DM84xx 를 위해서 변경사항이 있는지 확인만 하자 

  • ALSA Common API
ALSA의 일반적인 API로 아래 함수명과 설명을 보면 쉽게 사용법이 짐작이 간다. 
관련 세부내용들은 생략하도록 하겠다. 
Commonly Used APIs
NameDescription
snd_pcm_openOpens a PCM stream
snd_pcm_closeCloses a previously opened PCM stream
snd_pcm_hw_params_anyFill params with a full configuration space for a PCM
snd_pcm_hw_params_test_ <>Test the availability of important parameters like number of channels, sample rate etc. For e.g. snd_pcm_hw_params_test_format, snd_pcm_hw_params_test_rate etc.
snd_pcm_hw_params_set_ <>Set the different configuration parameters. For e.g. snd_pcm_hw_params_set_format, snd_pcm_hw_params_set_rate etc.
snd_pcm_hw_paramsInstall one PCM hardware configuration chosen from a configuration space
snd_pcm_writeiWrite interleaved frames to a PCM
snd_pcm_readiRead interleaved frames from a PCM
snd_pcm_preparePrepare PCM for use
snd_pcm_dropStop a PCM dropping pending frames
snd_pcm_drainStop a PCM preserving pending frames


아래의 ALSA의 Playback or Capture도 간단하게 짜기 싫다면, ALSA Tool을 간단하게 이용하도록하자. 

1.1 ALSA의 PLAYBACK FLOW


ALSA를 이용하여 기본적으로 Playback하는 flow로 그리 어렵지 않으며 거의 다른 일반 Linux System Call과 거의 유사하다. 

  1. Playback Mode로 Open
  2. hw parameter 관련설정 (format/acess type/ sample rate/ channel )
  3. write로 재생시작 


1.2 ALSA 의 CAPTURE FLOW


상위와 동일 
  1. Capture Mode로 Open
  2. hw parameter 관련설정 (format/acess type/ sample rate/ channel )
  3. read로 녹음시작 


관련내용출처 

2/22/2016

Audio-ALSA SOC Framework (Kernel)

1. ALSA KERNEL Driver 전체구성

아래는 DM368 IPNC의 기준으로 보겠으며 다른 SoC로 가면 전체구조가 변경이 될 수도 있겠지만, 
거의 근본적으로 구성은 AP/SoC의 관련 Driver 만들어서 ALSA Interface에 맞게 연결하여 동작하는 구조가 비슷하므로, 관련부분을 알아보도록하자.

User에서는 ALSA만 보면 되니 복잡하지 않지만, Driver 개발자에서는 제법 복잡한 구조이다.

OSS 와 ALSA 전체구조 및 ALSA 설명 

TI ALSA Codec Driver 세부구성파악


  • 각 디렉토리 구성 
   sound
   sound/core/
   sound/soc/codecs
   sound/soc/davinci
   sound/soc

  •  각 디렉토리의 사용되어지는 파일구성
./sound/core/pcm_lib.o
./sound/core/snd-pcm.o
./sound/core/init.o
./sound/core/memory.o
./sound/core/jack.o
./sound/core/sound.o
./sound/core/timer.o
./sound/core/pcm.o
./sound/core/pcm_timer.o
./sound/core/device.o
./sound/core/control.o
./sound/core/pcm_memory.o
./sound/core/misc.o
./sound/core/snd-page-alloc.o
./sound/core/info.o
./sound/core/snd-timer.o
./sound/core/pcm_misc.o
./sound/core/snd.o
./sound/core/memalloc.o
./sound/core/pcm_native.o
./sound/soc/soc-dapm.o
./sound/soc/soc-utils.o
./sound/soc/codecs/tlv320aic3x.o
./sound/soc/codecs/snd-soc-tlv320aic3x.o
./sound/soc/davinci/snd-soc-davinci.o
./sound/soc/davinci/davinci-evm.o
./sound/soc/davinci/davinci-i2s.o
./sound/soc/davinci/davinci-pcm.o
./sound/soc/davinci/snd-soc-davinci-i2s.o
./sound/soc/davinci/snd-soc-evm.o
./sound/soc/soc-core.o
./sound/soc/snd-soc-core.o
./sound/soc/soc-cache.o
./sound/soc/soc-jack.o
./sound/soundcore.o
./sound/sound_core.o
./sound/last.o

  • TI에서 제공하는 Audio 관련 부분 설명 
아래의 Link는 보면, TI에서 제공하는 Audio 구조를 파악이 가능하다.
      http://processors.wiki.ti.com/index.php/Processor_SDK_Linux_Audio

2. ALSA의 SOC 기본 Driver 구조 

DM368의 SOC를 세부적으로 본다며, 아래와 같으며, 각 설명 Driver의 구성은 다음과 같다.

  • Codec Driver :   sound/soc/codecs/tlv320aic3x.c
  • Platform Driver:  sound/soc/davinci/davinci-i2s.c
  • Machine Driver:  sound/soc/davinci/davinci-evm.c 

  • SOC의 기본구조 설명  
      http://processors.wiki.ti.com/index.php/Sitara_Linux_Audio_Driver_Overview
   

2.1  Machine Driver 

TI-SOC의 구성 , 아래와 같이 Machine Driver가 기본설정하고 , Platform과 Codec을 연결을 해준다.
정확히 cpu_dai와 codec_dai를 mapping을 하여 동작한다.


$ vi sound/soc/davinci/davinci-evm.c 
#define AUDIO_FORMAT (  SND_SOC_DAIFMT_DSP_A | \
                        SND_SOC_DAIFMT_CBM_CFM | \
                        SND_SOC_DAIFMT_IB_NF) 

static struct snd_soc_dai_link dm365_evm_dai = {
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
        .name = "TLV320AIC3X",
        .stream_name = "AIC3X",
        .cpu_dai_name = "davinci-mcbsp",        // CPU에서 사용하는 Audio Driver name , sound/soc/davinci/davinci-i2s.c  
        .codec_dai_name = "tlv320aic3x-hifi",   // CODEC에서 등록한 SOC DAI 이름 sound/soc/codecs/tlv320aic3x.c
        .init = evm_aic3x_init,
        .codec_name = "tlv320aic3x-codec.1-0018",
        .ops = &evm_ops,
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
        .name = "Voice Codec - CQ93VC",
        .stream_name = "CQ93",
        .cpu_dai_name = "davinci-vcif",
        .codec_dai_name = "cq93vc-hifi",
        .codec_name = "cq93vc-codec",
#endif
        .platform_name = "davinci-pcm-audio",    //  sound/soc/davinci/davinci-pcm.c  ( platform driver )
};

/* davinci dm365 evm audio machine driver */
static struct snd_soc_card dm365_snd_soc_card_evm = { // SOC Card  등록 
        .name = "DaVinci DM365 EVM",
        .dai_link = &dm365_evm_dai,
        .num_links = 1,
};

static int __init evm_init(void)
{
.......
        } else if (machine_is_davinci_dm365_evm() ||  machine_is_davinci_dm365_ipnc() || machine_is_davinci_dm368_ipnc()) {
                evm_snd_dev_data = &dm365_snd_soc_card_evm;
                index = 0;
        }

        evm_snd_device = platform_device_alloc("soc-audio", index);     ///sound/soc/soc-core.c 와 연결 
        if (!evm_snd_device)
                return -ENOMEM;
        platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
        ret = platform_device_add(evm_snd_device);
        if (ret)
                platform_device_put(evm_snd_device);
....
}

module_init(evm_init);  // module init 하게 되면 아래 순서  

 soc_probe -> snd_soc_register_card -> snd_soc_instantiate_cards -> snd_soc_instantiate_card(struct snd_soc_card *card)

  • 아래에서 Kernel Log에서 확인 가능 


ALSA device list:
             #0: DaVinci DM365 EVM



2.2 Platform Driver

TI에서 제공하는 Audio Driver McBSP or McASP 이며 이는 EDMA와 연결하여 동작한다.
그리고, 아래와 같이 PCM Driver와 연동이 되어 동작이 된다.


  • PCM Driver 
PCM Interface Driver로 , Platform Driver 라고 부른다. Machine Driver와 연결이 되어 있으며, PCM의 관련처리를 이곳에서 처리한다.
APP에서 PCM을 OPEN할 경우부터 기본설정되는 부분이 아래에 다 들어가 있다.

$ vi ./sound/soc/davinci/davinci-pcm.c  // PCM Driver로 File 정보를 여기서 처리 그리고, EDMA 처리 등을 담당. 

static struct snd_pcm_hardware pcm_hardware_playback = {     // ALSA의 기본 Playback 관련설정  
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
        .formats = (SNDRV_PCM_FMTBIT_S16_LE),
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
        .formats = (SNDRV_PCM_FMTBIT_S16_LE),
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
                  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
                  SNDRV_PCM_RATE_KNOT),
        .rate_min = 8000,
        .rate_max = 96000,
        .channels_min = 2,
        .channels_max = 2,
        .buffer_bytes_max = 128 * 1024,  
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
        .periods_min = 16,
        .periods_max = 255,
        .fifo_size = 0,
};

static struct snd_pcm_hardware pcm_hardware_capture = {     // ALSA의 기본 Capture 관련설정  
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE),
        .formats = (SNDRV_PCM_FMTBIT_S16_LE),
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
                  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
                  SNDRV_PCM_RATE_KNOT),
        .rate_min = 8000,
        .rate_max = 96000,
        .channels_min = 2,
        .channels_max = 2,
        .buffer_bytes_max = 128 * 1024,
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
        .periods_min = 16,
        .periods_max = 255,
        .fifo_size = 0,
};

/*
    PCM 기본 동작 Driver  ,  PCM OPEN시,  HW_PARAM 정보,  TRIGGER, 이는 곳 EDMA와 연결을 시킨다. 
*/
static struct snd_pcm_ops davinci_pcm_ops = {  
        .open =         davinci_pcm_open,
        .close =        davinci_pcm_close,
        .ioctl =        snd_pcm_lib_ioctl,
        .hw_params =   davinci_pcm_hw_params,  //HW_PARAM 설정 , ALSA APP에 호출될 때 호출 .
        .hw_free =      davinci_pcm_hw_free,
        .prepare =      davinci_pcm_prepare,   // TI EDMA 준비 
        .trigger =      davinci_pcm_trigger,   // TI EDMA Control 
        .pointer =      davinci_pcm_pointer,     
        .mmap =         davinci_pcm_mmap,   // DMA 관련 MMAP
};

static struct snd_soc_platform_driver davinci_soc_platform = {
        .ops =          &davinci_pcm_ops,
        .pcm_new =      davinci_pcm_new,
        .pcm_free =     davinci_pcm_free,
};

static int __devinit davinci_soc_platform_probe(struct platform_device *pdev)
{
        return snd_soc_register_platform(&pdev->dev, &davinci_soc_platform);
}


static struct platform_driver davinci_pcm_driver = {
        .driver = {
                        .name = "davinci-pcm-audio",
                        .owner = THIS_MODULE,
        },

        .probe = davinci_soc_platform_probe,
        .remove = __devexit_p(davinci_soc_platform_remove),
};


  • CPU AUDIO Driver
TI사에 제공하는 SOC Driver (McBSP)이며, 이는 PCM Interface Driver와 같이 동작하며,실질적인 SoC의 Audio Driver이다.
McBSP가 HW Codec과 연결되어 실질적인 역할하며, Interface는 I2S이지만, 다른 것으로 변경가능하다 (DSP Mode)

$ vi ./sound/soc/davinci/davinci-i2s.c   //MCBSP의 Main Controller 로, 실제 CPU Dai에 연결된다.
static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
        .startup        = davinci_i2s_startup,
        .shutdown       = davinci_i2s_shutdown,
        .prepare        = davinci_i2s_prepare,
        .trigger        = davinci_i2s_trigger,
        .hw_params      = davinci_i2s_hw_params,   // HW_PARAM 설정 
        .set_fmt        = davinci_i2s_set_dai_fmt,
        .set_clkdiv     = davinci_i2s_dai_set_clkdiv,

};

static struct snd_soc_dai_driver davinci_i2s_dai = {  // Capture/Playback I2S Interface의 동작범위 와 Format 정의  

        .playback = {
                .channels_min = 2,
                .channels_max = 2,
                .rates = DAVINCI_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .capture = {
                .channels_min = 2,
                .channels_max = 2,
                .rates = DAVINCI_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &davinci_i2s_dai_ops,

};
static int davinci_i2s_probe(struct platform_device *pdev)
{
  ..... 
  EDMA 관련 초기화 

       ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
        if (ret != 0)
                goto err_free_mem;
}

static struct platform_driver davinci_mcbsp_driver = {
        .probe          = davinci_i2s_probe,
        .remove         = davinci_i2s_remove,
        .driver         = {
                .name   = "davinci-mcbsp",
                .owner  = THIS_MODULE,
        },
};
static int __init davinci_i2s_init(void)
{
      return platform_driver_register(&davinci_mcbsp_driver);
}
module_init(davinci_i2s_init);


2.3 HW Codec Driver

Codec Driver는 구조가 거의 비슷하며, I2C Driver로 Codec을 Control 하게되어 각 설정을 변경하고, 등록을 하는 것이다. 
이는 soc_dai를 등록하여 동작하게 한다.
Codec를 동작하게 하기위해서는 미리 I2C Device를 등록을 해야 동작이 가능하다.
(Audio-ALSA SOC Codec Driver 참조)


$ vi ./sound/soc/codecs/tlv320aic3x.c   // Codec Driver 현재 AIC3100으로 변경 중. 서로 호환이 되지 않음 

static struct snd_soc_dai_driver aic3x_dai = {
        .name = "tlv320aic3x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 1,
                .channels_max = 2,
                .rates = AIC3X_RATES,
                .formats = AIC3X_FORMATS,},
        .capture = {
                .stream_name = "Capture",
                .channels_min = 1,
                .channels_max = 2,
                .rates = AIC3X_RATES,
                .formats = AIC3X_FORMATS,},
        .ops = &aic3x_dai_ops,
};

static int aic3x_i2c_probe(struct i2c_client *i2c,
                           const struct i2c_device_id *id)
{
......
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_aic3x, &aic3x_dai, 1);
}

static struct i2c_driver aic3x_i2c_driver = {
        .driver = {
                .name = "tlv320aic3x-codec",
                .owner = THIS_MODULE,
        },
        .probe  = aic3x_i2c_probe,
        .remove = aic3x_i2c_remove,
        .id_table = aic3x_i2c_id,
};
static inline void aic3x_i2c_init(void)
{
        int ret;
        ret = i2c_add_driver(&aic3x_i2c_driver);
        if (ret)        printk(KERN_ERR "%s: error regsitering i2c driver, %d\n",     __func__, ret);
}
static int __init aic3x_modinit(void)
{
        int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&aic3x_i2c_driver);
        if (ret != 0) {
                printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
                       ret);
        }
#endif
        return ret;
}
module_init(aic3x_modinit);



  • AM335x 와 DM81xx Driver Guide
아래의 사이트를 보면, 각 CPU 마다 Driver의 구조 및 FLOW  ,구조를 설명을 하고 있다.
  http://processors.wiki.ti.com/index.php/AM335x_Audio_Driver's_Guide
  http://processors.wiki.ti.com/index.php/DM81xx_AM38xx_Audio_Driver_User_Guide



3. ALSA Card 등록 및 확인 

  • Kernel Log 확인 
linux kernel log에서 아래와 같이 ALSA device에 추가 되었는지 확인을 하자.
DM368인 경우, TLVAIC3x 코덱을 사용을 하면, 2개의 McBSP Driver의 충돌로 인하여 제대로 등록이 되지 않는다.

ALSA device list:
             #0: DaVinci DM365 EVM


  • ALSA Card 등록확인
ALSA에 등록하여 사용하도록 하자 
$ vi sound/soc/davinci/davinci-evm.c 
/* davinci dm365 evm audio machine driver */
static struct snd_soc_card dm365_snd_soc_card_evm = {
        .name = "DaVinci DM365 EVM",
        .dai_link = &dm365_evm_dai,
        .num_links = 1,
};

static int __init evm_init(void)
{
.........
        } else if (machine_is_davinci_dm365_evm() ||  machine_is_davinci_dm365_ipnc() || machine_is_davinci_dm368_ipnc()) {
                evm_snd_dev_data = &dm365_snd_soc_card_evm;
                index = 0;
       }
        evm_snd_device = platform_device_alloc("soc-audio", index);
        if (!evm_snd_device)
                return -ENOMEM;

        platform_set_drvdata(evm_snd_device, evm_snd_dev_data);
        ret = platform_device_add(evm_snd_device);
        if (ret)
                platform_device_put(evm_snd_device);

........
}
module_init(evm_init);
module_exit(evm_exit);


  • ALSA AUDIO Driver 등록 확인 
아래와 같이 davinci-mcbsp platform_device를 등록을 하였지만,이 platfor_driver가 현재 두개가 존재하여 문제가 됨
이중  davinci-i2s.c  선택하여 사용함
  1. ./sound/soc/davinci/davinci-i2s.c     // 이 McBSP는 일반 Codec 사용
  2. ./arch/arm/mach-davinci/mcbsp.c    // 이 McBSP는 Voice Codec을 사용시 사용


$ vi ./arch/arm/mach-davinci/board-dm368-ipnc.c 

static struct snd_platform_data dm365_evm_snd_data = {
        .asp_chan_q = EVENTQ_3,
};

$ vi ./arch/arm/mach-davinci/dm365.c

static struct resource dm365_asp_resources[] = {
        {
                .start  = DAVINCI_DM365_ASP0_BASE,
                .end    = DAVINCI_DM365_ASP0_BASE + SZ_8K - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
                .start  = DAVINCI_DMA_ASP0_TX,
                .end    = DAVINCI_DMA_ASP0_TX,
                .flags  = IORESOURCE_DMA,
        },
        {
                .start  = DAVINCI_DMA_ASP0_RX,
                .end    = DAVINCI_DMA_ASP0_RX,
                .flags  = IORESOURCE_DMA,
        },
};

static struct platform_device dm365_asp_device = {
        .name           = "davinci-mcbsp",                   // 현재 충돌 중. McBSP Driver 가 두 개 
        .id             = -1,
        .num_resources  = ARRAY_SIZE(dm365_asp_resources),
        .resource       = dm365_asp_resources,
};

platform_device_register(&dm365_asp_device);


2/16/2016

Audio-ALSA SOC Framework-Codec Driver ( Kernel)

1. Hardware 기본구성 및 설정

  • TI McASP 와 AIC3x HW Codec 의 연결사항 



  • BCLK (BIT CLOCK)        :  Codec Clock 제공  (Master)
  • WCLK (WORD CLOCK)  :  Codec Frame Sync 제공 (Master) 
  • RX Data                     :  RX Data (Encoding Data)
  • TX Data                     :  TX Data (Decoding Data )

위 구성을 보면 AIC3x CODEC은 BCLK과 WCLK(Frame sync)를 제공하며, Data는 이 Frame Sync의 Timing에 맞추어 전송하고 받는다.
기본적인 통신은 Synchronous이며 설정에 따라 Interface의 방식은 변경되어 진다..

  http://processors.wiki.ti.com/index.php/Sitara_Linux_Audio_Hardware_Overview

1.1 ALSA SOC-DAIFMT 설정


아래의 설정은 ALSA에서 설정하는 SOC 설정모드이며, Codec 입장에서 기술된다.

  • CBM: Codec Clock Master:  Codec Chip Clock 제공
  • CFM: Codec Frame Sync Master: Codec Chip Frame Sync 제공

CODEC는 위와 같이 CLOCK과 Frame Sync(WCLK)을 제공을 한다.
그러므로, CODEC이 BCLK Master Frame Sync Master이므로, SND_SOC_DAIFMT_CBM_CFM 이다.

  • 둘 사이의 Master/Slave 관련결정 
$ vi include/sound/soc-dai.h
#define SND_SOC_DAIFMT_CBM_CFM          (0 << 12) /* codec clk & FRM master */
#define SND_SOC_DAIFMT_CBS_CFM          (1 << 12) /* codec clk slave & FRM master */
#define SND_SOC_DAIFMT_CBM_CFS          (2 << 12) /* codec clk master & frame slave */
#define SND_SOC_DAIFMT_CBS_CFS          (3 << 12) /* codec clk & FRM slave */

  • 둘 사이의 실제적인 Interface 결정 과 Clock 
$ vi include/sound/soc-dai.h
#define SND_SOC_DAIFMT_I2S              0 /* I2S mode */
#define SND_SOC_DAIFMT_RIGHT_J          1 /* Right Justified mode */
#define SND_SOC_DAIFMT_LEFT_J           2 /* Left Justified mode */
#define SND_SOC_DAIFMT_DSP_A            3 /* L data MSB after FRM LRC */
#define SND_SOC_DAIFMT_DSP_B            4 /* L data MSB during FRM LRC */
#define SND_SOC_DAIFMT_AC97             5 /* AC97 */


#define SND_SOC_DAIFMT_NB_NF            (0 << 8) /* normal bit clock + frame */
#define SND_SOC_DAIFMT_NB_IF            (1 << 8) /* normal BCLK + inv FRM */
#define SND_SOC_DAIFMT_IB_NF            (2 << 8) /* invert BCLK + nor FRM */
#define SND_SOC_DAIFMT_IB_IF            (3 << 8) /* invert BCLK + FRM */

가장 일반적인게 I2S이며, DSP Mode A/B 혹은 AC97인데, Codec Chip이 지원되는 거에 따라 변경해서 사용하자. 

  • DM368의 최종결정 
$ vi ./sound/soc/davinci/davinci-evm.c // 현재 DM368 설정

#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
                SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) 



  • AIC3100 의 지원되는 I2S와 DSP Mode 
아래는 AIC3100이 DSP MODE Interface방식이며, 이는 McBSP or McASP와 같이 설정을 확인해봐야한다.
Offset은 McBSP의 Data Delay에 같이 설정해야하며
Offset을 주느냐에 따라 DSP_B모드가 되며,NB_NF의 선택 BCLK과 WCLK의 극성선택이다.




2. I2C driver 기본확인사항  

HW Codec의 I2C Driver는 거의 동일하며, 실제적인 Codec의 관련설정을 하는 것이므로, 사용시 반드시 Codec Datasheet와 함께 봐야한다.

2.1 Audio Codec 등록 확인
     
아래와 같이 기본 board에서 등록이 되어있는지 확인하고, Kernel config에서지원되는 것을 확인을 하자.
만약 지원이 되지 않는다면, 이제 Audio Codec Driver를 가져와서, 이를 Porting하자 .
아래와 같이 등록을 해야, 실제 Audio Codec Driver에서 발견가능하다.
보통 Codec Driver 들은 여러종류의 칩의 지원을 하므로, 아래와 같이 board에서 이름을 정확히 정해줘야한다.

현재 DM368에, AIC3100을 올려서 수정하고 있다.


       A. DM368

$ vi arch/arm/mach-davinci/board-dm368-ipnc.c 

static struct i2c_board_info i2c_info[] = {
        {
                I2C_BOARD_INFO("tlv320aic3x", 0x18), // AIC3100의 7bit Address는 0x18 설정 
        },
};

static void __init evm_init_i2c(void)
{
        davinci_init_i2c(&i2c_pdata);
        i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
}


       B. DM355

아래와 같이, plaform_data에 argument를 넣어 전달이 가능하다.
그러면, i2c_probe할 때, struct i2c_client *i2c 에서  i2c->dev.platform_data 전달 받을 수 있다.

$ vi arch/arm/mach-davinci/board-dm355-evm.c 
static struct i2c_board_info dm355evm_i2c_info[] = {
        {       I2C_BOARD_INFO("dm355evm_msp", 0x25),
                .platform_data = dm355evm_mmcsd_gpios,
        },
        /* { plus irq  }, */
        { I2C_BOARD_INFO("tlv320aic33", 0x1b), },
};

static void __init evm_init_i2c(void)
{
        davinci_init_i2c(&i2c_pdata);

        gpio_request(5, "dm355evm_msp");
        gpio_direction_input(5);
        dm355evm_i2c_info[0].irq = gpio_to_irq(5);

        i2c_register_board_info(1, dm355evm_i2c_info,
                        ARRAY_SIZE(dm355evm_i2c_info));
}

2.2 Audio Codec Driver 기본동작 

    AIC3x Driver 즉 HW Codec Driver 예제이며 구조는 다음과 같다.
    1. module init 이 호출되면서, i2c_add_driver 호출하여, i2c driver 를 등록
    2. 이미 등록된 I2C device가 있으면, 이를 찾아 probe를 호출 (platform_driver 구조와 동일)
    3. aic3x_i2c_probe 는 snd_soc_register_codec 사용하여 Codec Driver를 등록한다.
    4. aic3x_dai를 snd_soc_dai를 등록하여 이는 codec_dai 와 cpu_dai와 mapping 동작함

    $ vi sound/soc/codecs/tlv320aic3x.c 
    
    static const struct i2c_device_id aic3x_i2c_id[] = {
            [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
            [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
            [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
            { }
    };
    MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
    
    
    /* machine i2c codec control layer */
    static struct i2c_driver aic3x_i2c_driver = {
            .driver = {
                    .name = "tlv320aic3x-codec",
                    .owner = THIS_MODULE,
            },
            .probe  = aic3x_i2c_probe,       // 이미 i2c_register_board_info 했을 경우, probe를 실행  
            .remove = aic3x_i2c_remove,
            .id_table = aic3x_i2c_id,
    };
    
    static inline void aic3x_i2c_init(void)
    {
            int ret;
    
            ret = i2c_add_driver(&aic3x_i2c_driver);
            if (ret)
                    printk(KERN_ERR "%s: error regsitering i2c driver, %d\n",
                           __func__, ret);
    }
    
    static inline void aic3x_i2c_exit(void)
    {
            i2c_del_driver(&aic3x_i2c_driver);
    }
    
    
    static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
            .set_bias_level = aic3x_set_bias_level,  // Reset , 초기화 Codec의 상태별로 설정 
            .reg_cache_size = ARRAY_SIZE(aic3x_reg), // Cache Size
            .reg_word_size = sizeof(u8),                  
            .reg_cache_default = aic3x_reg,          // Codec Default Setting. 
            .probe = aic3x_probe,                    // aic3x_probe**  
            .remove = aic3x_remove,
            .suspend = aic3x_suspend,
            .resume = aic3x_resume,
    };
    
    
    #define AIC3X_RATES     SNDRV_PCM_RATE_8000_96000
    #define AIC3X_FORMATS   (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
                             SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
    
    static struct snd_soc_dai_ops aic3x_dai_ops = {
            .hw_params      = aic3x_hw_params,      // CODEC 관련 설정
            .digital_mute   = aic3x_mute,           // 
            .set_sysclk     = aic3x_set_dai_sysclk, // CLOCK 관련 설정
            .set_fmt        = aic3x_set_dai_fmt,    // Interface 설정 (format 설정)
    };
    
    static struct snd_soc_dai_driver aic3x_dai = {
            .name = "tlv320aic3x-hifi",
            .playback = {
                    .stream_name = "Playback",
                    .channels_min = 1,
                    .channels_max = 2,
                    .rates = AIC3X_RATES,
                    .formats = AIC3X_FORMATS,},
            .capture = {
                    .stream_name = "Capture",
                    .channels_min = 1,
                    .channels_max = 2,
                    .rates = AIC3X_RATES,
                    .formats = AIC3X_FORMATS,},
            .ops = &aic3x_dai_ops,
    };
    static int aic3x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) // Codec Driver 등록
    { .......
    ret = snd_soc_register_codec(&i2c->dev,
                     &soc_codec_dev_aic3x, &aic3x_dai, 1);  //snd_soc_dai_driver 등록 이는 추후 SOC와 Mappping 
    ......
    }
    


    3. Codec Porting 시 체크사항 

    현재 AIC3100을 사용해야하는데, AIC3x와 정확히 호환되지 않는다.
    그리고, AIC3100 Driver (AM3xxx 계열지원) 지원이 되지만 DM368 Kernel ALSA Version과 다르다.
    커널 간에 ALSA의 아래사항을 확인해보자.


    3.1  ALSA Framework 확인 

    Kernel의 ALSA 기본 Framework 부분을 확인하자.

         A. ALSA 기본 header 체크사항 

            include/sound/soc.h   
            include/sound/soc-dapm.h

         B. Codec 에 의존된 header 체크 

          현재 TI TLV Series 사용하므로, 아래의 header를 체크하자. (AIC3100 사용)
          만약 Wolfson사의 WM Series를 사용한다면, 다른 header를 체크하자.

           include/sound/tlv.h

    3.2 I2C Mapping  확인

    Code driver 는 요즘 거의 Cache에 Mapping 시켜서 사용하는 것 같다.
    기본적으로  사용하고 싶은 register size 만큼 cache에 등록하고,
    별도의 kernel/drivers/base/regmap/regmap-i2c.ko 필요한 것 같은데,  불행히도 DM368은 지원하지 않는다.

    그래서 그냥 아래와 같이 직접 I2C에 연결해서 사용했다.
    Kernel config에 포함이 되어있지 않다면, 아래와 같이 직접 연결하여 사용해야한다.

    static int aic3100_read(struct snd_soc_codec *codec, unsigned int reg)
    {
            struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
            int ret=0;
                    
            reg = (reg & 0xff);        
            ret = i2c_smbus_read_byte_data(aic3x->control_data, reg);
            if (ret < 0) printk("%s error addr=%x \n",__func__,reg);
            return ret;
    }
    
    
    static int aic3100_write(struct snd_soc_codec *codec, unsigned int reg,
                           unsigned int value)
    {
            struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
            int ret=0;
            
            reg = (reg & 0xff);
            value = (value & 0xff);
    
            ret = i2c_smbus_write_byte_data(aic3x->control_data, reg, value);
            if (ret < 0) printk("%s error addr=%x val=%x \n",__func__,reg,value);
    
            return ret;
    }
    

    3.3 CODEC 과 CPU 의 Interface 설정

    TI Audio Driver는 현재 아래와 같은 구조로 동작하며, 다른 Driver 일 경우 변경 될 수 있다.
    모든 것이 hw_param 의해 설정이 되며, 아래와 같이 개별적으로 Driver 마다 존재한다.

    ALSA에서 hw_param가 호출이 되면, EVM 및 개별 machine, codec, cpu, platform driver의 hw_param이 호출이 된다.
    ALSA는 간단하지만 내부 Driver구조들은 제법 많이 복잡하다 관련내용은 추후 다시 설명 

    • evm_hw_param 인 경우 
    아래와 같이 Codec Driver의 CPU Driver의 set_fmt 설정 하고, Codec Driver의 sys_clk을 호출하여 설정한다.

    $ vi ./sound/soc/soc-core.c
    soc_pcm_hw_params  // 개별가 존재하면, hw_params 호출  machine  ,codec, cpu, plaftform, 
    
    
    $ vi ./sound/soc/davinci/davinci-evm.c 
    
    #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
                    SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) 
    
    static int evm_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
    {
    .....
            /* set codec DAI configuration */
            ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); // CODEC Driver 에  set_fmt 함수 호출, 
            if (ret < 0)
                    return ret;
    
           /* set cpu DAI configuration */
            ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); // McBSP Driver 에  format 적용
            if (ret < 0)
                    return ret;
    
            /* set the codec system clock */
            ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); // Codec Driver 의 set_sysclk 호출
            if (ret < 0)
                    return ret;
    ...
    }
    


    2/15/2016

    Audio-ALSA Framework

    1. ALSA의 기본구조 

    ALSA(Advanced Linux Sound Architecture)로 요즘 거의 AP/SoC들은 ALSA의 기반에 맞추어 각 Driver들을 만들어 이곳에 등록하여 동작하도록 구성한다.
    그래서 ALSA Format? 이 존재하고 각 AP/SoC 업체들은 각 자신들의 BSP Driver를 이 Format에 맞추어 동작가능하도록 하고 호환성을 높인다. 

    1.1 OSS와 ALSA 

    OSS (Open Sound System) 약어로 Linux 2.4에서 공식적으로 사용을 했다고 한다.이때도 Audio Driver 수정했지만, 모르고 수정했다.
    ALSA(Advanced Linux Sound Architecture)로 Linux에서만 사용이 되며, Kernel version 2.5에서 부터 추가가 되었다고 한다. 
    ALSA라는 이름 부각되는 것은 Linux Kernel 이 2.4 -> 2.5로 변경되면서 Driver 전체구조자체가 Platform 구조로 변경되었기 때문인 것 같다. 

    사실 Audio 관련 Driver는 Kernel 2.4 때 주로 많이 직접 Audio Driver를 만들었지만, 그때는  OSS라는 이름을 잘 못들은 것 같다.  
    Kernel 2.4 Audio Driver 의 경우는 좀 제 각각인데다가, 필요에따라 확장하고 그랬다. 
    또한 각 Audio Chip Vendor에 따라 구조역시 조금씩 다르다. 

    OSS 관련내용
      https://en.wikipedia.org/wiki/Open_Sound_System
      http://www.opensound.com/pguide/oss.pdf


    1.2 TI 사의 ALSA 전체구조

    ALSA의 기본 전체구조는 아래와 같으며, 다른 SOC 플랫폼도 유사하다.
    아래 구조는 TI사의 Sitara의 구조에서 가져왔다.
    자세한 내용은 아래의 페이지 참조

    TI사의 ALSA 전체구조 




    관련내용참조  
      https://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture
      http://processors.wiki.ti.com/index.php/Sitara_Linux_Audio_Driver_Overview

    Linux의 Audio Driver의 기본구조는 ALSA Framework이며, 이에 관련된 Project는 다음과 같으며, 위와 같다.

    ALSA 관련문서 
      http://www.alsa-project.org/main/index.php/Documentation
      http://www.alsa-project.org/main/index.php/Download


    2. ALSA의 전체구조 

    ALSA의 구조를 간단히 2단계로 나누면 간단하다, KERNEL과 APP이다.
    하지만 세부화로 나누게되면, KERNEL도 COMMON한 부분이 있고, 포팅을 해야하는 부분이 있기에 이를 또 나누게 된다.
    그리고, 이를 USER에게 기능을 제공을 하면, Alsa User Lib가 이를 가지고 사용을 한다.


    2.1 ALSA SOC CORE (KERNEL)

    • Codec Driver  :  AIC31x, AIC3100  Audio Codec Driver를 말하며, I2C로 Driver이다. 
    • Platform Driver: TI인 경우 주로 McBSP or McASP Audio Driver이며, DMA기능을 포함한다.
    • Machine Driver: Codec과 Platform Driver를 연결시켜주는 Driver이며, Machine에 대한 설정 담당한다. 

    Embeded Linux에서는 해당 Chip마다 각 ALSA Soc Driver를 제공하며,Framework이 SOC마다 약간 상이하며, Version에 따라 다를 수 있다.
    ALSA Library와 직접적으로 통신을 하며, 기능을 제공을 한다.
      http://www.alsa-project.org/main/index.php/ASoC


    2.2 ALSA Library   (USER)

    • ALSA PCM 기본설명
      http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html
      http://www.alsa-project.org/alsa-doc/alsa-lib/
      http://www.alsa-project.org/main/index.php/ALSA_Library_API


    2.3 ALSA Application (USER)

    • ALSA를 이용한 다양한 Application Program들
    ex) gstremer, sndlib 등 native version에 따라 지원되는 app이 다르다.
      http://www.alsa-project.org/main/index.php/Applications
    Android로 가면, Hal이 될수도 있다.

    • ALSA Test (alsa-utils)
    ALSA Test program (aplay, arecord, amixer )
      http://alsa.opensrc.org/Alsa-utils
      ftp://ftp.alsa-project.org/pub/utils/

    2/14/2016

    Audio-ALSA Debug 및 TEST 및 기능 확인

    1. ALSA 기본 구성 및 확인  

    • PC 관련 설정 및 ALSA PC에서 설치 
    PC에 관련된 ALSA 부분이지만, 설정 및 관련된 부분은 참조하기에 좋은 것 같아

         https://en.wikipedia.org/wiki/Advanced_Linux_Sound_Architecture
         http://alsa.opensrc.org/ALSA_Setup_Guide
         https://wiki.gentoo.org/wiki/ALSA


    1.1 ALSA 환경설정 및 관련사이트 

    ALSA의 환경설정/etc/asound.conf  (아직 미확인 및 추후 사용해본후 수정)

    • 환경설정  (ALSA 환경설정)
         http://www.alsa-project.org/main/index.php/Asoundrc
         http://www.mjmwired.net/kernel/Documentation/sound/alsa/ALSA-Configuration.txt

    • ALSA Project 및 ALSA UTIL 기본사용법  
    ALSA 기본 프로젝트 및 소스  기본 사용법
         http://www.alsa-project.org/main/index.php/Main_Page
         https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture


    1.2 ALSA와 UDEV의 조합 

    임베디드에서는 잘 사용하지 않겠지만, udev를 이용하여 ALSA 설정을 적용가능한것 같다.
    USB를 Sound Card 적용하여 sound card를 등록하여 동적으로 등록하여 사용하는 것 같다.
    추후 사용할 기회가 있으면 사용후 완성.

         http://alsa.opensrc.org/Udev



    2.  ALSA 의 기본 확인 사항 

    ALSA 기본 설정값들의 이해와 XRUN 문제 

      https://ahyuo79.blogspot.com/2014/04/alsa.html


    2.1 device file 확인 과 OSS Mapping  

    ALSA device File 확인 , ALSA를 사용한 이후로 부터 /dev 구성은 아래와 같이 구성이 된다. OSS를 사용한다면 구성이 달라진다.

     $ ls -l /dev/snd/
    /dev/snd/controlC0
    /dev/snd/pcmC0D0c
    /dev/snd/pcmC0D0p
    /dev/snd/timer
    
    ALSA PCM devices to OSS devices mapping
    =======================================
    
    /dev/snd/pcmC0D0[c|p]  -> /dev/audio0 (/dev/audio) -> minor 4
    /dev/snd/pcmC0D0[c|p]  -> /dev/dsp0 (/dev/dsp)     -> minor 3
    /dev/snd/pcmC0D1[c|p]  -> /dev/adsp0 (/dev/adsp)   -> minor 12
    /dev/snd/pcmC1D0[c|p]  -> /dev/audio1              -> minor 4+16 = 20
    /dev/snd/pcmC1D0[c|p]  -> /dev/dsp1                -> minor 3+16 = 19
    /dev/snd/pcmC1D1[c|p]  -> /dev/adsp1               -> minor 12+16 = 28
    /dev/snd/pcmC2D0[c|p]  -> /dev/audio2              -> minor 4+32 = 36
    /dev/snd/pcmC2D0[c|p]  -> /dev/dsp2                -> minor 3+32 = 39
    /dev/snd/pcmC2D1[c|p]  -> /dev/adsp2               -> minor 12+32 = 44
    
    


    2.2 ALSA의 PROC 구조 및 정보확인

    • PROC 기본 구조
    /proc/asound/card0/
                       |-- codec#0
                       |-- id
                       |-- oss_mixer
                       `-- pcm3p    // Channel, Playback, 
                           |-- info
                           `-- sub0
                               |-- hw_params   // 만약 동작 중이면, 정보를 볼수 있다. 
                               |-- info
                               |-- prealloc
                               |-- prealloc_max
                               |-- status
                               `-- sw_params  // 만약 동작 중이면 정보를 볼 수 있다.
    
    
    
    

    ALSA Proc 문서 
      http://alsa.opensrc.org/Proc_asound_documentation

    • ALSA Util을 이용하여 DM368 TEST 및 DEBUG 
    가장 기본 Playback 과 Capture TEST 진행 
    $ aplay /root/test.wav 
    
    $ arecord -f S16_LE -r48000 -c 2  -d 10 /root/test.wav    // -f : format  , -r samplerate , -c channel , -d time  
    

    • ALSA 의 Proc 구성확인 (DM365로 분석)
    간단하게 ALSA의 내부구성을 분석을 해보도록 하자 
    $ cat /proc/asound/cards
     0 [EVM            ]:  - DaVinci DM365 EVM
                          DaVinci DM365 EVM
    
    $ cat /proc/asound/card0/pcm0c/info
    $ cat /proc/asound/card0/pcm0p/info
    card: 0
    device: 0
    subdevice: 0
    stream: PLAYBACK
    id: AIC3X tlv320aic3x-hifi-0
    name:
    subname: subdevice #0
    class: 0
    subclass: 0
    subdevices_count: 1
    subdevices_avail: 1 
    
    $ cat /proc/asound/card0/pcm0c/sub0/status 
    $ cat /proc/asound/card0/pcm0p/sub0/status 
    state: RUNNING
    owner_pid   : 3893
    trigger_time: 3158.514143919         
    tstamp      : 3162.679480670          // time stamp 
    delay       : 32768                        // buffer_size , latency , now playback 
    avail       : 0                               // xrun check
    avail_max   : 0
    -----
    hw_ptr      : 0
    appl_ptr    : 32768                        // buffer_size
    
    $ cat /proc/asound/card0/pcm0c/sub0/sw_params
    $ cat /proc/asound/card0/pcm0p/sub0/sw_params 
    tstamp_mode: NONE
    period_step: 1
    avail_min: 2048
    start_threshold: 32768                   // default setting is buffer size, 
    stop_threshold: 32768                   // default setting is buffer size ,
    silence_threshold: 0
    silence_size: 0
    
    $ cat /proc/asound/card0/pcm0c/sub0/hw_params
    $ cat /proc/asound/card0/pcm0p/sub0/hw_params 
    access: RW_INTERLEAVED
    format: S16_LE
    subformat: STD
    channels: 2                             // channel check ,   2 ch x 16 bit = frame size 
    rate: 48000 (48000/1)
    period_size: 2048                     // 32768/16 = 2048      , buffer_size / periods_min
    buffer_size: 32768                    // 2048 x 16 = 32768    , buffer_bytes_max  (128 * 1024)  /  4 ( 2ch * 16bit)



    관련내용부분 
      http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m___s_w___params.html
      http://alsa.opensrc.org/Aplay
      http://furmuwon.egloos.com/m/11090448


    3. ALSA UTILS (추후 정리 및 삭제)

    요즘 거의 모든 SDK에는 ALSA UTIL과 관련된 Library는 들어가 있다.
    물론 Android도 관련부분이 다 있다.
      http://www.alsa-project.org/main/index.php/SoundcardTesting
      http://www.alsa-project.org/main/index.php/Download

      ALSA Util에는 많이 사용하는 Tool 은 aplay,arecord,amixer

      http://alsa.opensrc.org/Aplay

    hw: 0, 0
        cardnumber , device number


    aplay -vv -Dhw:0,0  /opt/ipnc/alarm_1_16K.wav

    speaker-test

    http://forum.falinux.com/zbxe/index.php?document_srl=549296&mid=lecture_tip


    https://en.wikibooks.org/wiki/Configuring_Sound_on_Linux/HW_Address

    http://www.sabi.co.uk/Notes/linuxSoundALSA.html



    cat /proc/asound/card0/pcm0p/sub0/hw_params



    $ vi ./sound/soc/davinci/davinci-evm.c

    #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
                    SND_SOC_DAIFMT_CBS_CFM | SND_SOC_DAIFMT_IB_NF)

             SND_SOC_DAIFMT_CBM_CFS / MCBSP_CLKR


    CLKR
    DAVINCI_MCBSP_SRGR_CLKSM   0
    DAVINCI_MCBSP_PCR_SCLKME   1

    SCLKME Bit CLKSM Bit
    in PCR in SRGR Input Clock for Sample Rate Generator
    0 0 Signal on MCBSP_CLKS pin
    0 1 McBSP internal input clock
    1 0 Signal on MCBSP_CLKR pin
    1 1 Signal on MCBSP_CLKX pin

    소스
    https://github.com/torvalds/linux/tree/master/sound/soc/codecs


    #define SND_SOC_DAIFMT_CBM_CFM (1 << 12) -- codec clk & FRM master --
    #define SND_SOC_DAIFMT_CBS_CFM (2 << 12) -- codec clk slave & FRM master --
    #define SND_SOC_DAIFMT_CBM_CFS (3 << 12) -- codec clk master & frame slave -
    #define SND_SOC_DAIFMT_CBS_CFS (4 << 12) -- codec clk & FRM slave --

    http://processors.wiki.ti.com/index.php/Omapl137_linux_audio_driver


    http://processors.wiki.ti.com/index.php/DM81xx_AM38xx_Audio_Driver_User_Guide


    http://egloos.zum.com/furmuwon/v/10996415

    https://developer.ridgerun.com/wiki/index.php/Audio_codec_AIC3x_register_dump
    http://crystalcube.co.kr/123

    4/10/2014

    Audio-ALSA APP Interface (정리가 필요)

    1. ALSA APP Interface 

    ALSA의 Application에서 주로 사용하는 Interface는 다음과 같다.
    1. PCM interface:  PCM을 open하여 capture와 playback을 조절한다. 
    2. Timer interface: Timer를 제공하여, PCM Interface와 함게 event를 제공하다.
    3. Mixer interface:  Volume 조절 및 PCM의 설정 제공한다. 

    Real-Time Audio Kernel ( Latency 관련부분)
      http://elinux.org/images/8/82/Elc2011_lorriaux.pdf
      http://free-electrons.com/doc/embedded_linux_audio.pdf


    1.1 ALSA PCM Buffer 구성 및 설명

    아래의 그림은 기본적인 2Ch인 Stereo 방식의 Buffer 구성이며 기본구성 



    Buffer는 일반적으로 Stereo 로 사용할 경우 1 Frame: 2 CH * 2byte로 구성이 되지만, 각 PCM의 설정에 따라 변경된다. 
    이  기본 Frame은 기본 한구성이 있는데 다음과 같다. 

    • frame_size (기본 2 Ch 설정)
    ALSA의 기본단위는 Frame이며 아래와 같이 계산된다. 

      1 Frame :  Number of CH * Number of Sample 
      (Ex:  2CH * 1 Sample: 2 * 2byte = 4byte) 

    그리고, period 로 frame을 묶어 주기적으로 Timer interrupt를 사용하여 전송하며, 이 전체사이즈를 buffer라고 한다. 
    ALSA는 위와 같이 playback or capture를  위와 같이 buffer size 만큼의 delay 가 발생하며,즉 latency 발생된다.  

    • period_size 
    주기적으로 Frame을 묶어 보내는 전송하는 Frame Size를 이 buffer의 크기를 조절하면 , PMIC와 같이 사용하는 AP에는 Power Consumption 영향을 미치며
    Buffer를 크기를 크게하면, Power consumption 약간 증가한다 그래서 적절히 다운시켜 사용해야 하는 것으로 보인다. 

    struct snd_pcm_hardware 구조체관련내용 
      http://egloos.zum.com/furmuwon/v/11008641
    ALSA buffer overflow(XRUN)
      https://ffmpeg.org/pipermail/ffmpeg-user/2013-March/014090.html

    •  buffer_size 
    편히 상, Buffer Frame이라고 부르겠으며, 상위 그림의 전체 Buffer size이다. Period Frame들이 모여서 한 Block이 된 Frame을 말한다.
    설정은  buffer_size   = period_size x period_count, 주로 Application에서 사용한다.
    이 크기는 playback 시 delay가 되는 latency를 의미한다.


    1.2  Threshold 설정 과 XRun 

    Threshold 설정은 주로 보면 Buffer Xrun을 조절하기 위해서 사용되어지며, 관련설정들의 의미를 정확하게 알아두자 

    • start_threshold
    audio stream, data들이 들어왔을 경우, start point, 시작지점 설정을 말하며, underrun과 관련이 있다.
    (The start threshold parameter is used to determine the start point in the stream.)

    설정방법
      if available frames >= threadhold, it is possible to play or capture 
        i.e: period_count * period_size
        snd_pcm_sw_params_set_start_threshold

    start threadhold 인 경우,이설정값이 지난 후에, 동작가능하다.


    • stop_threshold
    overrun(buffer의 overflow)을 체크하기 위한 level이라고 생각하면 되며. 이 값을 넘으면,자동적으로 stop이 된다. 
    (the stop threshold parameter is used to automatically stop the running stream when the available samples crosses this boundary for checking underrun or overun.)

    설정방법
      if available frames >= threadhold , pcm is automatically stoping the running system.
              for playback, capture threadhold > buffer size with xrun
              for playback, capture threadhold = buffer size without xrun
              
              if (avail >= runtime->stop_threshold)  //pcm_lib.c 
               xrun(substream);
               
        i.e: period_count * period_size   snd_pcm_sw_params_set_stop_threshold
    start or stop threshold를 보면 start point와 stop point를 정확히 설정하는 것이다.
    threshold라는 것이 문턱 or 설정한 level이라고 생각하면되겠다.

    이는 xrun과 밀접한 관련이 있으며 audio가 주로 멈추는 현상은 이 xrun 현상이며, 
    이부분은 period_size 과 stop_Threadhold 값을 잘 조절해서 맞추어 가며 재 설정해 간다


    • silence threshold
    playback 시 미리 silent sample을 채워 이를 재생을 하는 것이다.
    (sample's number filled with silence ahead of the current application pointer for playback.)
    i.e: 0 
      snd_pcm_sw_params_set_silence_threshold
    

    • XRUN 
    overrun 과 underrun을 말하며, 두 device의 속도차이로 인하여 buffer empty or overflow를 말한다.
    이는 두 device간의 read 와 write 간의 속도차로 발생하여, buffer 부족하면, underrun 이라고 하고,
    buffer가 넘치면 이를 overrun이라고 한다.

    자주 발생하는 XRUN 현상
    1. playback일 경우, empty buffer로 인하여, underrun 발생 하여 재생불능 상태 발생
    2. capture 일 경우, buffer가 데이타 넘쳐 overrun 발생하여, 더이상 녹음 불능 발생  

    XRUN Debug
      http://www.alsa-project.org/main/index.php/XRUN_Debug

    • Sound buffers and Data Transfer 
    ALSA의 buffer는 Application buffer와 Hardware buffer가 있으며, 이곳에서는 Hardware buffer의 구성은 제외하겠다. Application Buffer Size 는 buffer_size이며, 이는


    • 기본예제 및 Buffer의 기본개념 XRUN 설명
      http://www.linuxjournal.com/node/6735/print
      http://www.alsa-project.org/main/index.php/FramesPeriods


    1.3  Kernel PCM Driver 관련설정 

    • Kernel driver에서 PCM에 관한 설정 
    Kernel Driver에서 제공되는 기능으로  Driver에서 Audio의 기능을 설정을 하여, Application의 설정을 제한을 한다.

    $ vi include/sound/pcm.h      //   DM368 
    struct snd_pcm_hardware {
            unsigned int info;              /* SNDRV_PCM_INFO_* */
            u64 formats;                    /* SNDRV_PCM_FMTBIT_* */
            unsigned int rates;             /* SNDRV_PCM_RATE_* */
            unsigned int rate_min;          /* min rate */
            unsigned int rate_max;          /* max rate */
            unsigned int channels_min;      /* min channels */
            unsigned int channels_max;      /* max channels */
            size_t buffer_bytes_max;        /* max buffer size */
            size_t period_bytes_min;        /* min period size */
            size_t period_bytes_max;        /* max period size */
            unsigned int periods_min;       /* min # of periods */
            unsigned int periods_max;       /* max # of periods */
            size_t fifo_size;               /* fifo size in bytes */
    };
    
    $ vi ./sound/soc/davinci/davinci-pcm.c  //DM368 HW Setting . PCM Driver 
    
    static struct snd_pcm_hardware pcm_hardware_capture = {
            .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                     SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                     SNDRV_PCM_INFO_PAUSE),
            .formats = (SNDRV_PCM_FMTBIT_S16_LE),
            .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                      SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                      SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
                      SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
                      SNDRV_PCM_RATE_KNOT),
            .rate_min = 8000,
            .rate_max = 96000,
            .channels_min = 2,
            .channels_max = 2,
            .buffer_bytes_max = 128 * 1024,     // max buffer_size  =128 x 1024 = 131072
            .period_bytes_min = 32,               // min  period_size = 32 
            .period_bytes_max = 8 * 1024,       // max period_size  = 8x 1024 =  8192
            .periods_min = 16,                       //  min period_count 
            .periods_max = 255,                    //   max period_count
            .fifo_size = 0,
    };
    static struct snd_pcm_hardware pcm_hardware_playback = {
            .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                     SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                     SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
            .formats = (SNDRV_PCM_FMTBIT_S16_LE),
            .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                      SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                      SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
                      SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
                      SNDRV_PCM_RATE_KNOT),
            .rate_min = 8000,
            .rate_max = 96000,
            .channels_min = 2,
            .channels_max = 2,
            .buffer_bytes_max = 128 * 1024,
            .period_bytes_min = 32,
            .period_bytes_max = 8 * 1024,
            .periods_min = 16,
            .periods_max = 255,
            .fifo_size = 0,
    };  
    

      http://www.alsa-project.org/~tiwai/writing-an-alsa-driver/ch05s05.html#pcm-interface-runtime-hw


    • HW/SW Params 확인 
    관련부분들 확인 
    $ vi ./include/sound/pcm.h
    struct snd_pcm_runtime {
            /* -- Status -- */
            struct snd_pcm_substream *trigger_master;
            struct timespec trigger_tstamp; /* trigger timestamp */
            int overrange;
            snd_pcm_uframes_t avail_max;
            snd_pcm_uframes_t hw_ptr_base;  /* Position at buffer restart */
            snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
            unsigned long hw_ptr_jiffies;   /* Time when hw_ptr is updated */
            unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
            snd_pcm_sframes_t delay;        /* extra delay; typically FIFO size */
    
            /* -- HW params -- */
            snd_pcm_access_t access;        /* access mode */
            snd_pcm_format_t format;        /* SNDRV_PCM_FORMAT_* */
            snd_pcm_subformat_t subformat;  /* subformat */
            unsigned int rate;              /* rate in Hz */
            unsigned int channels;          /* channels */
            snd_pcm_uframes_t period_size;  /* period size */
            unsigned int periods;           /* periods */
            snd_pcm_uframes_t buffer_size;  /* buffer size */
            snd_pcm_uframes_t min_align;    /* Min alignment for the format */
            size_t byte_align;
            unsigned int frame_bits;
            unsigned int sample_bits;
            unsigned int info;
            unsigned int rate_num;
            unsigned int rate_den;
    
            /* -- SW params -- */
            int tstamp_mode;                /* mmap timestamp is updated */
            unsigned int period_step;
            snd_pcm_uframes_t start_threshold;
            snd_pcm_uframes_t stop_threshold;
            snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
                                                    noise is nearest than this */
            snd_pcm_uframes_t silence_size; /* Silence filling size */
            snd_pcm_uframes_t boundary;     /* pointers wrap point */
    
            snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
            snd_pcm_uframes_t silence_filled; /* size filled with silence */
    
            union snd_pcm_sync_id sync;     /* hardware synchronization ID */
            ......
    


    2. Application 의 설정속성 

    Linux Kernel에서 ALSA관련 Device Interface를 제공하고, App은 이것을 이용을 DATA전송및 Control을 하게되고, Timer를 이용한다.
    하지만 Embedded에서는 이 모든 기능을 다 제공하지는 않는다.
    대부분 Control과 PCM과 Timer를 제공하고 다른 기능은 거의 제공하지는 않는다.

    • Control Interface (/dev/snd/controlCX)
    • Mixer Interface (/dev/snd/mixerCXDX)
    • PCM Interface (/dev/snd/pcmCXDX)
    • Raw MIDI Interface (/dev/snd/midiCXDX)
    • Sequencer Interface (/dev/snd/seq)
    • Timer Interface (/dev/snd/timer)
    관련내용참조 
      http://www.alsa-project.org/alsa-doc/alsa-lib/
      http://www.alsa-project.org/main/index.php/ALSA_Library_API


    2.1 PCM Device Interface

    Application 에서 주요하게 다루는 Interface는 PCM이다.  (/dev/snd/pcmCxDx)
    PCM Interface를 이용하여, Audio Data를 전송하여 Play하고 Capture를 하며, Block Mode와 Non Block Mode 및 XRUN 감지 및 parameter 관리등을 다룬다.

    아래는 TI의  PCM device file을 보여주며, 모든 ALSA의 기능을 제공해주지는 않는다.
    Embedded 에서는 아래와 같이 기본기능만을 사용한다.

    • 실제의 사용되어지는 예 
    Caputre/Playback/Timer/Control 만 사용되며, App에서는 이를 이용하여 ALSA를 이용 

    $ ls /dev/snd/
    controlC0  pcmC0D0c   pcmC0D0p   timer
    

    관련내용 
      http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html


    2.2 Timer Interface

    Timer는 ALSA를 NonBlock 모드사용할 경우 주로 사용하는 것 같다.
      http://www.alsa-project.org/alsa-doc/alsa-lib/timer.html
      http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2timer_8c-example.html#a1


    2.3  HW/SW Parameters 

    Kernel에서 Parameter의 기능의 제한이 되고, Application에서 이 설정의 변경이 가능하다.
    이 설정을 변경을 함으로써, 성능 및 XRUN 문제의 오류를 방지하고 변경하자.

      .channels                  =  mono or stero 으로 설정 (2 or 1)
      .rate                      =  Sample rate 값 설정
      .period_size               =  P-Frame으로 설정.   (unit: frame)
      .period_count              =  P-Frame Count  
      .format                    =  PCM_FORMAT_S16_LE or PCM_FORMAT_S32_LE , 다른 값.
      .start_threshold           =  minum ,
      .silence_threshold         =  0
      .stop_threshold            =  > buffer size


    default
        start_threshold   : period_count * period_size, default setting values 
        stop_threshold    : period_count * period_size, default setting values (XRUN control)
        silence_threshold : 0
       
       frame_size                =  num of channel * a sample        (i.e 2* 1 sample = 4 byte)
       buffer_size               =  period_size * period_count       (unit: frame)       
       period_bytes              =  period_size * bytes_per_frame    (unit: frame)
       bytes_per_frame           =  channels * bytes_per_sample      (unit: byte)    (4byte ,Stereo-2Ch)) 

    http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_min_8c-example.html#a6


    • period_size 
    주기적으로 한 Frame 크기로 데이타를 전송하는 단위를 말하며, Interrupt와 밀접한 연관이 있으며, 이 buffer를 조절하면 , 
    PMIC와 같이 사용하는 것에는 Power Consumption 영향을 미치며. 크기를 크게하면, Power consumption 약간 증가한다.
    그래서 적절히 다운시켜 사용해야 하는 것 같다.

    아래는 Period Size를 구하는 간단한 예제이다, Interrupt Time을 아래와 같이 설정하고
       period_size  = Sample rate  x ( Interrupt Time) , unit : frame
       5292            =   44100 x (P Time 120/1000, interrupt time)  
       5760            =   48000 x (P Time 120/1000, interrupt time)
                                     
                           (ABE, Only 48KHz used. if used 44.1KHz resampling by Speex )
                            참고로,  48KHz로만 사용할것이다, 44.1KHz는 Resample이 필요할 것이다.

        1056        = 48000 x  (22/1000)


      아래의 Link는 byte단위로 계산을 했지만, 위 계산은 Frame 단위이다. 
      

    •  buffer_size
    편히 상, Buffer Frame이라고 부르며, Period Frame들이 모여서 한 Block이 된 Frame을 말한다. 
    설정은  buffer_size   = period_size x period_count, 주로 Application에서 사용한다.

    1.   B Time: P Time *  period_count= Latency

                      B Frame이 소비되는 시간을 말하며, 정확하게는 Latency.
                                           
                     ** Latency: Buffer Time

    아래는 tinyalsa lib의 기본소스
        https://github.com/tinyalsa/tinyalsa


    3. ALSA  기타 설정 항목 설명 (추후 삭제) 
      
    boundary
    sw_param 1937768448
    avail
    runtime->status->hw_ptr    : the number of frame that kernel write. 
    runtime->control->appl_ptr : the number of frame that application write,  x4 ( 2byt and 2xchannel)
    Playback (pcm_mmap_playback_avail/ pcm.c application)
    avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr;
     
    Capture  (pcm_mmap_capture_avail)
    int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
    start threadhold
    The start threshold parameter is used to determine the start point in stream.
    sample's number     if available frames >= threadhold, it is possible to play or capture 
    i.e: period_count * period_size
    snd_pcm_sw_params_set_start_threshold


    stop threadhold
    the stop threshold parameter is used to automatically stop the running stream when the available samples crosses this boundary.
    for checking underrun or overun.
    sample's number   if available frames >= threadhold , pcm is automatically stoping the running system.
     for playback, capture threadhold > buffer size with xrun
     for playback, capture threadhold = buffer size without xrun
     
     if (avail >= runtime->stop_threshold)  //pcm_lib.c 
    xrun(substream);
    i.e: period_count * period_size
    snd_pcm_sw_params_set_stop_threshold
    • Android HAL


    • ALSA 기본 예제 


    1/03/2014

    Audio-ALSA OMAP Framework

    1. OMAP 기본 ALSA 구성 

    다음은 OMAP의 기본 ALSA  기본 Framewor이며, 기존 Audio Driver와 다른것이 있다면,HDMI와 확장형 Controler가 많다. 
    사실 직접 일했을 때 Source를 분석을 했어야 했는데, 지금 간단히 정리한다.



    아래 사이트에 가면 OMAP과 Codec의 설명이 잘 나오며, 기존 Davinchi Series와 차이점이라면, PMIC 사용 및 McPDM지원, HDMI 지원 등이다.
    전에는 HDMI 때문에 SiliconImage사의 Chip도 사용을 하고 했는데, OMAP은 편해진것 같다.
    OMAP에 대한 Audio관한  HW 정보 및 구성은 아래에서 확인하자.


    • OMAP Audio Framework 및 기본구성정보
    http://omappedia.org/wiki/Audio_Drive_Arch


    • ALSA SOC 과 ALSA 부분 Link 
    http://omappedia.org/wiki/Audio_Developers_Info


    • Pulse Audio 관련 (아직 사용못해봄)
      https://wiki.archlinux.org/index.php/PulseAudio
      http://omappedia.org/wiki/Ubuntu_PA
      https://www.freedesktop.org/wiki/Software/PulseAudio/

    • OMAP 관련 Audio 전체 설명 (상위 부분 Link)
      http://omappedia.org/wiki/Audio_Drivers_Domain_Wiki


    2. OMAP Android Info


    • OMAP Ref
      http://www.ti.com/pdfs/wtbu/OMAP4430_4460_4470_PUBLIC_TRM_Addendum_ABE_HAL_vH.pdf
      http://omappedia.org/wiki/4AI.1.5_OMAP4_ICS_Blaze_AIC_AIC3262_SW_Release3c


    • Android HAL
      http://source.android.com/devices/audio_implement.html


    3. OMAP 관련 LINK

    • OMAP 관련부분 Link
      http://omappedia.org/wiki/Linux_OMAP_Kernel_Main

    • OMAP Gstreamer
      http://omappedia.org/wiki/Gstreamer_Project_Main