1. 程式人生 > >alsa音訊採集和播放 (麥克風)

alsa音訊採集和播放 (麥克風)

Alsa音訊採集

#include <stdio.h>

#include <malloc.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <getopt.h>

#include <fcntl.h>

#include <ctype.h>

#include <errno.h>

#include <limits.h>

#include <time.h>

#include <locale.h>

#include <assert.h>

#include <sys/poll.h>

#include <sys/uio.h>

#include <sys/time.h>

#include <sys/signal.h>

#include <asm/byteorder.h>

#include <pthread.h>

#include "alsa/asoundlib.h"

#include "porting_mic.h"

#include "porting_debug.h"

/********************************************************************************************************

 *                                        Defines                                                       *

 ********************************************************************************************************/

/* do function and check return */

#define DOFUNC_CHECK(func) \

    do{ \

        ret = func; \

        if ( ret < 0 ) \

        { \

            HISI_ERR(PORT_MODULE_MIC, "(err)%s failed, ret = %s", #func, errno); \

            goto LAB_ERR; \

        } \

    }while ( 0 )

#define SAMPLES 320 /*取樣個數,320個就返回一次,太大了會等待太久*/

#define LOOP_BUF_LEN (1024*16)

#define min(x,y) ({ \

    typeof(x) _x = (x); \

    typeof(y) _y = (y); \

    (void) (&_x == &_y);\

    _x < _y ? _x : _y; })

/* 迴圈buffer */

typedef struct {

    pthread_mutex_t mutex;

    BYTE_T buffer[LOOP_BUF_LEN]; 

    UINT32_T in;

    UINT32_T out;

} loop_buf_t;

/* 儲存音訊資料到檔案 */

//#define RECORD_DATA

/********************************************************************************************************

 *                                        Global Variables                                              *

 ********************************************************************************************************/

/********************************************************************************************************

 *                                        Local Variables                                               *

 ********************************************************************************************************/

/* used for DOFUNC_CHECK, save the function name in func_name */

static CHAR_T func_name[64];

static CHAR_T *pfunc;

static UINT32_T g_mic_handle = 0;

static pthread_t g_mic_thread = 0;

static UINT32_T g_thread_flag = 0;

static UINT32_T g_mic_status = 0; /* 0:stop capture; 1:start capture */

static UINT32_T g_puting_data = 0;

static loop_buf_t ring_buf;

static loop_buf_t *PMIC_buf = &ring_buf;

static UINT32_T g_bits_per_frame;

static UINT32_T g_bits_per_sample;

static BYTE_T *g_buf_getdata = NULL;

static BYTE_T *g_buf_transfchn = NULL;

static BYTE_T *g_buf_transfrate = NULL;

static INT32_T chn_mul = 1;/* 1:單聲道; 2:雙聲道*/

static INT32_T rate_mul = 1; /* 基於8000Hz, 1:8000; 2:16000; 3:24000 ... */

snd_pcm_sframes_t (*readi_func)(snd_pcm_t *handle, void *buffer, snd_pcm_uframes_t size);

#ifdef RECORD_DATA

    FILE *g_original_fp = NULL;

    FILE *g_send_fp = NULL;

#endif

/********************************************************************************************************

 *                                        Local Functions Declaring                                     *

 ********************************************************************************************************/

static INT32_T mic_init_loop_buf(loop_buf_t *buf);

static INT32_T mic_release_loop_buf(loop_buf_t *buf);

static INT32_T mic_put_loop_buf(loop_buf_t *buf, BYTE_T *buffer, UINT32_T len);

static INT32_T mic_get_loop_buf(loop_buf_t *buf, BYTE_T *buffer, UINT32_T len);

static VOID mic_lock_buf(loop_buf_t *buf);

static VOID mic_unlock_buf(loop_buf_t *buf);

static INT32_T mic_get_params(snd_pcm_format_t *format, UINT32_T *channels, UINT32_T *rate);

static INT32_T mic_set_params(UINT32_T handle);

static INT32_T mic_pcm_read(INT32_T ophandle, BYTE_T *data, UINT32_T rcount);

VOID *mic_usb_task(VOID);

/********************************************************************************************************

 *                                        Global Functions                                              *

 ********************************************************************************************************/

INT32_T porting_mic_init(VOID)

{

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    CHECK_MODULE_INIT_STATUS(PORT_MODULE_MIC);

    SET_MODULE_INIT_STATUS(PORT_MODULE_MIC);

    HISI_INFO(PORT_MODULE_MIC, "(out)"); 

    return IPANEL_OK;

}

INT32_T  porting_mic_exit(VOID)

{

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    CHECK_MODULE_EXIT_STATUS(PORT_MODULE_MIC);

    SET_MODULE_EXIT_STATUS(PORT_MODULE_MIC);

    HISI_INFO(PORT_MODULE_MIC, "(out)");

    return IPANEL_OK;

}

/*********************************************************************

功能說明: 

開啟一個聲音採集裝置例項。 

引數說明: 

  輸入引數: 

index-指定 mic 的索引位置 

   輸出引數:無 

返  回: 

!= IPANEL_NULL: 返回開啟裝置的控制代碼

== IPANEL_NULL: 開啟裝置失敗。

************************************************************************/

UINT32_T ipanel_porting_mic_open(IPANEL_MIC_NOTIFY func)

{

    int ret;

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    ret = mic_open();

    if( ret == 0) goto LAB_ERR;

    /* 註冊音訊資料回撥函式 */

    readi_func = snd_pcm_readi;

    g_thread_flag = 1;

    g_mic_thread = ipanel_porting_task_create("umic", mic_usb_task, NULL, 5, 0x8000);

    if( g_mic_thread == 0 )

    {

        mic_close();

        goto LAB_ERR;

    }

#ifdef RECORD_DATA

    /***************************************************************

     g_original_fp儲存麥克風拿到的原始資料,readi_funcdata

     g_send_fp儲存傳給中介軟體的資料,ipanel_porting_mic_readdata

     ***************************************************************/

        g_original_fp = fopen("./save_from_capture_original_data.pcm", "w+");

        if(!g_original_fp)

        {

            HISI_ERR(PORT_MODULE_MIC, "opne file save_from_capture_original_data failed!");

            perror("open");

        }

        else

        {

            HISI_INFO(PORT_MODULE_MIC, "open save_from_capture_original_data file");

        }

        g_send_fp = fopen("./save_data_sending_ipanel.pcm", "w+");

        if(!g_send_fp)

        {

            HISI_ERR(PORT_MODULE_MIC, "opne file g_send_fp failed!");

            perror("open");

        }

        else

        {

            HISI_INFO(PORT_MODULE_MIC, "open save_from_capture_original_data file");

        }

#endif

    /************************************************************************

     g_buf_getdata: 存放readi_func讀到的原始資料

     g_buf_transfchn: 原始資料資料轉成單聲道資料後存放到這個buf

     g_buf_transfrate: 取樣率轉換成8K後的資料,該buf資料就是上傳給中介軟體的資料

     ************************************************************************/

    g_buf_getdata = malloc(SAMPLES * g_bits_per_frame / 8);

    if (g_buf_getdata == NULL)

    {

        HISI_ERR(PORT_MODULE_MIC, "g_buf_getdata get memory failed!");

    }

    g_buf_transfchn = malloc(SAMPLES * g_bits_per_sample / 8);

    if (g_buf_transfchn == NULL)

    {

        HISI_ERR(PORT_MODULE_MIC, "g_buf_transfchn get memory failed!");

    }

    g_buf_transfrate = malloc(SAMPLES);

    if (g_buf_transfrate == NULL)

    {

        HISI_ERR(PORT_MODULE_MIC, "g_buf_transfrate get memory failed!");

    }

    HISI_INFO(PORT_MODULE_MIC,"(out)");

    return  g_mic_handle;

LAB_ERR:

    return IPANEL_NULL;

}

/********************************************************************************************************

功能說明:

讀取聲音取樣資料。

引數說明:

輸入引數:

handle –聲音採集裝置例項控制代碼

buf - 指向資料塊的指標

len - buf的長度

輸出引數:

buf:讀取的取樣資料

返  回:

>=0: 函式執行成功,返回讀取的資料長度;

IPANEL_ERR: 函式執行失敗。

********************************************************************************************************/

INT32_T ipanel_porting_mic_read(UINT32_T handle, BYTE_T *buf, UINT32_T len)

{

    INT32_T DataLen;

    porting_verb(PORT_MODULE_MIC, "(in) expect len = %d", len); 

    if (g_puting_data)

    {

        porting_verb(PORT_MODULE_MIC, "(out) return 0"); 

        return 0;

    }

    DataLen = 0;

    if (g_mic_status)

    {

        mic_lock_buf(PMIC_buf);

        DataLen = mic_get_loop_buf(PMIC_buf, buf, len);

        mic_unlock_buf(PMIC_buf);

    }

    porting_verb(PORT_MODULE_MIC, "(out) read DataLen = %d", DataLen); 

    return DataLen;

}

/************************************************************************************

功能說明: 

  關閉通過 ipanel_porting_mic_open 開啟的聲音採集裝置例項,同時要釋放可能存

在的待處理資料塊。 

引數說明: 

  輸入引數: 

  mic –聲音採集裝置例項控制代碼 

   輸出引數:無 

返  回: 

IPANEL_OK: 函式執行成功

IPANEL_ERR: 函式執行失敗。 

**********************************************************************************/

INT32_T ipanel_porting_mic_close(UINT32_T handle)

{

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    g_thread_flag = 0;

    ipanel_porting_task_destroy(g_mic_thread);

    mic_close();

#ifdef RECORD_DATA

    fclose(g_original_fp);

    fclose(g_send_fp);

#endif

    free(g_buf_getdata);

    free(g_buf_transfchn);

    free(g_buf_transfrate);

    HISI_INFO(PORT_MODULE_MIC,"(out)");

    return IPANEL_OK;

}

/************************************************************************************

功能說明:

對聲音採集裝置例項進行一個操作,或者用於設定和獲取聲音採集裝置例項的引數和屬性。

引數說明:

    輸入引數:

        handle –聲音採集裝置例項控制代碼

        op - 操作命令

        typedef enum

        {

            IPANEL_MIC_START = 1,

            IPANEL_MIC_STOP = 2,

            IPANEL_MIC_CLEAR_BUFFER = 3,

            IPANEL_MIC_SET_PARAM = 4

        } IPANEL_MIC_IOCTL_e;

        arg – 操作命令所帶的引數,當傳遞列舉型或32位整數值時,arg可強制轉換成對應資料型別。

oparg的取值關係見下表:

        +-----------------------+-----------------------------------+--------------------+

        |Op                 |Arg                                |說明                |

        +-----------------------+-----------------------------------+--------------------+

        |IPANEL_MIC_START       |IPANEL_NULL                        |啟動聲音採集         |

        +-----------------------+-----------------------------------+--------------------+

        |IPANEL_MIC_STOP        |IPANEL_NULL                        |停止聲音採集         |

        +-----------------------+-----------------------------------+--------------------+

        |IPANEL_MIC_CLEAR_BUFFER|IPANEL_NULL                        |清空聲音採集快取     |

        +-----------------------+-----------------------------------+--------------------+

        |IPANEL_MIC_SET_PARAM   |指向IPANEL_PCMDES 型別的一個指標,   |設定取樣引數         |

        |                       |此時引數是個輸入輸出引數,如果裝置   |                    |

        |                       |沒有使用者指定的能力,則裝置將自身能   |                    |

        |                       |力在這個結構中返回     |                    |

        +-----------------------+-----------------------------------+--------------------+

  輸出引數:無

返  回:

IPANEL_OK: 函式執行成功;

IPANEL_ERR: 函式執行失敗。

**********************************************************************************/

INT32_T ipanel_porting_mic_ioctl(UINT32_T handle, IPANEL_MIC_IOCTL_e op, VOID *arg)

{

    INT32_T i;

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    if (handle != g_mic_handle)

    {

        HISI_ERR(PORT_MODULE_MIC, "(err) invalid handle!");

        return IPANEL_ERR;

    }

    switch(op)

    {

        case IPANEL_MIC_START:

        {

            HISI_INFO(PORT_MODULE_MIC, "IPANEL_MIC_START");

            if (1 == g_mic_status)

            {

                goto LABEL_OK;

            }

            g_mic_status = 1;

        }

        break;

        case IPANEL_MIC_STOP:

        {

            HISI_INFO(PORT_MODULE_MIC, "IPANEL_MIC_STOP");

            if(0 == g_mic_status)

            {

                goto LABEL_OK;

            }

            g_mic_status = 0;

            usleep(200);

            memset(PMIC_buf->buffer, 0, LOOP_BUF_LEN); 

            PMIC_buf->in = PMIC_buf->out = 0;

        }

        break;

        case IPANEL_MIC_CLEAR_BUFFER:

        {

            HISI_INFO(PORT_MODULE_MIC, "IPANEL_MIC_CLEAR_BUFFER");

            g_mic_status = 0;

            usleep(200);

            memset(PMIC_buf->buffer, 0, LOOP_BUF_LEN); 

            PMIC_buf->in = PMIC_buf->out = 0;

            g_mic_status = 1;

        }

        break;

        case IPANEL_MIC_SET_PARAM:

        {

            /* 中介軟體通過IPANEL_PCMDES設定音訊格式,現在固定為PCM */

            HISI_INFO(PORT_MODULE_MIC, "IPANEL_MIC_SET_PARAM TODO..");

        }

        break;

        default:

        {

            HISI_ERR(PORT_MODULE_MIC, "(err)invalid op");

            return IPANEL_ERR;

        }

    }

LABEL_OK:

    HISI_INFO(PORT_MODULE_MIC, "(out)");

    return IPANEL_OK;

}

/********************************************************************************************************

 *                                        Local Functions                                               *

 ********************************************************************************************************/

int mic_open(void)

{

    INT32_T ret;

    snd_pcm_t *phandle;

    snd_pcm_stream_t stream;

    CHAR_T *pcm_name = "default";

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    /* 錄音裝置固定為capture */

    stream = SND_PCM_STREAM_CAPTURE;

    if (!access("/dev/pcmC1D0c", F_OK))

    {

        HISI_INFO(PORT_MODULE_MIC, "access /dev/pcmC1D0c");

        pcm_name = "hw:1";

    }

    else if (!access("/dev/pcmC0D0c", F_OK))

    {

        HISI_INFO(PORT_MODULE_MIC, "access /dev/pcmC0D0c");

        pcm_name = "hw:0";

    }

    else

    {

        HISI_ERR(PORT_MODULE_MIC, "can not find capture device");

        goto LAB_ERR;

    }

    DOFUNC_CHECK(snd_pcm_open(&phandle, pcm_name, stream, 0));

    g_mic_handle = (UINT32_T)phandle;

    HISI_INFO(PORT_MODULE_MIC, "snd_pcm_open, device name %s, handle %d", pcm_name, g_mic_handle);

    mic_set_params(g_mic_handle);

    mic_init_loop_buf(PMIC_buf);

    HISI_INFO(PORT_MODULE_MIC,"(out)");

    return phandle;

LAB_ERR:

    return IPANEL_NULL;

}

int mic_close(void)

{

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    snd_pcm_close((snd_pcm_t *)g_mic_handle);

    g_mic_handle = 0;

    mic_release_loop_buf(PMIC_buf);

    HISI_INFO(PORT_MODULE_MIC,"(out)");

    return IPANEL_OK;

}

static INT32_T mic_init_loop_buf(loop_buf_t *buf)

{

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    memset(buf->buffer, 0, LOOP_BUF_LEN);

    buf->in = 0;

    buf->out = 0;

    pthread_mutex_init(&buf->mutex, NULL);

    HISI_INFO(PORT_MODULE_MIC, "(out)");

    return IPANEL_OK;

}

static INT32_T mic_release_loop_buf(loop_buf_t *buf)

{

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    pthread_mutex_destroy(&buf->mutex);

    HISI_INFO(PORT_MODULE_MIC, "(out)");

    return IPANEL_OK;

}

static INT32_T mic_put_loop_buf(loop_buf_t *buf, BYTE_T *buffer, UINT32_T len)

{

    UINT32_T num;

    porting_verb(PORT_MODULE_MIC, "(in)");

    len = min(len, LOOP_BUF_LEN - buf->in + buf->out);

    /* first put the data starting from buf->in to buffer end */

    num = min(len, LOOP_BUF_LEN - (buf->in & (LOOP_BUF_LEN - 1)));

    memcpy(buf->buffer + (buf->in & (LOOP_BUF_LEN - 1)), buffer, num);

    /* then put the rest (if any) at the beginning of the buffer */

    memcpy(buf->buffer, buffer + num, len - num);

    buf->in += len;

    if (buf->in == LOOP_BUF_LEN)

    {

        buf->in = 0;

    }

    porting_verb(PORT_MODULE_MIC, "(out) len = %d", len);

    return len;

}

static INT32_T mic_get_loop_buf(loop_buf_t *buf, BYTE_T *buffer, UINT32_T len)

{

    UINT32_T num;

    porting_verb(PORT_MODULE_MIC, "(in)");

    len = min(len, buf->in - buf->out);

    /* first get the data from buf->out until the end of the buffer */

    num = min(len, LOOP_BUF_LEN - (buf->out & (LOOP_BUF_LEN - 1)));

    memcpy(buffer, buf->buffer + (buf->out & (LOOP_BUF_LEN - 1)), num);

    /* then get the rest (if any) from the beginning of the buffer */

    memcpy(buffer + num, buf->buffer, len - num);

    buf->out += len;

    if (buf->out == buf->in) 

    {

        buf->out = 0;

        buf->in = 0;

    }

    porting_verb(PORT_MODULE_MIC, "(out) len = %d", len);

    return len;

}

VOID mic_lock_buf(loop_buf_t *buf)

{

    pthread_mutex_lock(&buf->mutex);

}

VOID mic_unlock_buf(loop_buf_t *buf)

{

    pthread_mutex_unlock(&buf->mutex);

}

static INT32_T mic_get_params(snd_pcm_format_t *format, UINT32_T *channels, UINT32_T *rate)

{

    INT32_T i;

    FILE * fp;

    CHAR_T *buf;

    CHAR_T *pt, *pt2;

    CHAR_T param[128];

    INT32_T size;

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    /***************************************************************************************

      拔掉或插入 USB MIC,單板上執行“ls /dev”命令,觀察 pcm字母開頭的 ALSA 裝置列表變化情況。

      以下是參考平臺插入 USB MIC 後 ALSA裝置列表: 

      pcmC0D0p    //C0表示card0D0表示device0p表示playback

      pcmC1D0c    //C1表示card1D0表示device0c表示capture

      硬體資訊不能定死,FormatChannelsRates要在裝置資訊檔案中讀取

      # cat /proc/asound/card1/stream0

    ***************************************************************************************/

    if (!access("/dev/pcmC1D0c", F_OK))

    {

        fp = fopen("/proc/asound/card1/stream0", "rt");

        if (NULL == fp)

        {

            HISI_ERR(PORT_MODULE_MIC, "card1 file open failed");

            goto LAB_ERR;

        }

    }

    else if(!access("/dev/pcmC0D0c", F_OK))

    {

        fp = fopen("/proc/asound/card0/stream0", "rt");

        if (NULL == fp)

        {

            HISI_ERR(PORT_MODULE_MIC, "card0 file open failed");

            goto LAB_ERR;

        }

    }

    else

    {

        HISI_ERR(PORT_MODULE_MIC, "can not find capture device");

        goto LAB_ERR;

    }

    buf = (CHAR_T *)malloc(2048 * sizeof(CHAR_T));

    if (NULL == buf)

    {

        HISI_ERR(PORT_MODULE_MIC, "buf malloc failed");

        fclose(fp);

        goto LAB_ERR;

    }

    size = fread(buf, sizeof(CHAR_T), 2048, fp);

    if (size <= 0)

    {

        HISI_ERR(PORT_MODULE_MIC, "file read failed");

        free(buf);

        buf = NULL;

        fclose(fp);

        goto LAB_ERR;

    }

    /* 檢索format */

    if((pt = strstr(buf, "S16_LE")) != 0 )

    {

        *format = SND_PCM_FORMAT_S16_LE;

        HISI_INFO(PORT_MODULE_MIC, "format is SND_PCM_FORMAT_S16_LE");

    }

    else

    {

        HISI_ERR(PORT_MODULE_MIC, "(err)unkonw format");

        goto LAB_ERR;

    }

    pt2 = buf;

    /* 檢索channels */

    while((pt = strstr(pt2, "Channels:")) != 0)

    {

        i = 0;

        while (*(pt+i) != '\n') i++;

        strncpy(param, pt, i);

        if (strchr(param, '1'))

        {

            *channels = 1;

            chn_mul = 1;

            break;

        }

        else if (strchr(param, '2'))

        {

            *channels = 2;

            chn_mul = 2;

            break;

        }

        else

        {

            HISI_ERR(PORT_MODULE_MIC, "(err)unkonw channels");

            goto LAB_ERR;

        }

        pt2 = pt+i;

    }

    HISI_INFO(PORT_MODULE_MIC, "channels is %d", *channels);

    pt2 = buf;

    /* 檢索rate */

    while((pt = strstr(pt2, "Rates:")) != 0)

    {

        i = 0;

        while (*(pt+i) != '\n') i++;

        strncpy(param, pt, i);

        if (strstr(param, " 8000") != 0)

        {

            HISI_INFO(PORT_MODULE_MIC, "Rates:8000");

            *rate = 8000;

            rate_mul = 1;

            break;

        }

        else if (strstr(param, "16000") != 0)

        {

            HISI_INFO(PORT_MODULE_MIC, "Rates:16000");

            *rate = 16000;

            rate_mul = 2;

            break;

        }

        pt2 = pt+i;

    }

    if(!pt)

    {

        porting_warn(PORT_MODULE_MIC, "unkonw rate, set default 8000");

        *rate = 8000;

        rate_mul = 1;

    }

    free(buf);

    buf = IPANEL_NULL;

    fclose(fp);

    HISI_INFO(PORT_MODULE_MIC, "(out)");

    return IPANEL_OK;

LAB_ERR:

    HISI_ERR(PORT_MODULE_MIC, "(err)");

    return IPANEL_ERR;

}

static INT32_T mic_set_params(UINT32_T handle)

{

    INT32_T ret;

    UINT32_T n;

    snd_pcm_format_t format;

    UINT32_T channels;

    UINT32_T rate;

    snd_pcm_t *phandle;

    snd_pcm_hw_params_t *params;

    snd_pcm_sw_params_t *swparams;

    UINT32_T buffer_time = 0;

    UINT32_T period_time = 0;

    snd_pcm_uframes_t buffer_frames = 0;

    snd_pcm_uframes_t chunk_size = 0;

    snd_pcm_uframes_t buffer_size;

    snd_pcm_uframes_t start_threshold, stop_threshold;

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    phandle = (snd_pcm_t *)handle;

    DOFUNC_CHECK(mic_get_params(&format, &channels, &rate));

    snd_pcm_hw_params_alloca(¶ms);

    snd_pcm_sw_params_alloca(&swparams);

    DOFUNC_CHECK(snd_pcm_hw_params_any(phandle, params));

    DOFUNC_CHECK(snd_pcm_hw_params_set_access(phandle, params, SND_PCM_ACCESS_RW_INTERLEAVED));

    DOFUNC_CHECK(snd_pcm_hw_params_set_format(phandle, params, format));

    DOFUNC_CHECK(snd_pcm_hw_params_set_channels(phandle, params, channels));

    DOFUNC_CHECK(snd_pcm_hw_params_set_rate_near(phandle, params, &rate, 0));

    DOFUNC_CHECK(snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0));

    if (buffer_time > 500000)

    {

        buffer_time = 500000;

    }

    period_time = buffer_time / 4;

    DOFUNC_CHECK(snd_pcm_hw_params_set_period_time_near(phandle, params, &period_time, 0));

    if (buffer_time > 0)

    {

        DOFUNC_CHECK(snd_pcm_hw_params_set_buffer_time_near(phandle, params, &buffer_time, 0));

    }

    else

    {

        DOFUNC_CHECK(snd_pcm_hw_params_set_buffer_size_near(phandle, params, &buffer_frames));

    }

    DOFUNC_CHECK(snd_pcm_hw_params(phandle, params));

    chunk_size = 1024;

    DOFUNC_CHECK(snd_pcm_hw_params_get_period_size(params, &chunk_size, 0));

    DOFUNC_CHECK(snd_pcm_hw_params_get_buffer_size(params, &buffer_size));

    if (chunk_size == buffer_size)

    {

        HISI_ERR(PORT_MODULE_MIC, "Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size);

        goto LAB_ERR;

    }

    DOFUNC_CHECK(snd_pcm_sw_params_current(phandle, swparams));

    n = chunk_size;

    DOFUNC_CHECK(snd_pcm_sw_params_set_avail_min(phandle, swparams, n));

    n = buffer_size;

    start_threshold = (double)rate / 1000000;

    if (start_threshold < 1)

    {

        start_threshold = 1;

    }

    if (start_threshold > n)

    {

        start_threshold = n;

    }

    DOFUNC_CHECK(snd_pcm_sw_params_set_start_threshold(phandle, swparams, start_threshold));

    stop_threshold = buffer_size;

    DOFUNC_CHECK(snd_pcm_sw_params_set_stop_threshold(phandle, swparams, stop_threshold));

    DOFUNC_CHECK(snd_pcm_sw_params(phandle, swparams));

    g_bits_per_sample = snd_pcm_format_physical_width(format);

    g_bits_per_frame = g_bits_per_sample * channels;

    HISI_INFO(PORT_MODULE_MIC, "(out)");

    return IPANEL_OK;

LAB_ERR:

    HISI_ERR(PORT_MODULE_MIC, "(err)");

    return IPANEL_ERR;

}

static INT32_T mic_pcm_read(INT32_T ophandle, BYTE_T *data, UINT32_T rcount)

{

    INT32_T r;

    UINT32_T count;

    snd_pcm_t *readhandle;

    porting_verb(PORT_MODULE_MIC, "(in)");

    readhandle = (snd_pcm_t*)ophandle;

    if(readhandle == 0) return IPANEL_ERR;

    count = rcount;

    while (count > 0)

    {

        r = readi_func(readhandle, data, count);

        if (r < 0) 

        {

            usleep(1000);

            return IPANEL_ERR;

        }

        else 

        {

            count -= r;

            data += r * g_bits_per_frame / 8;

        }

    }

    porting_verb(PORT_MODULE_MIC, "(out)");

    return rcount;

}

VOID *mic_usb_task(VOID)

{

    INT32_T i, ret = 0;

    INT32_T readlen;

    INT32_T tmp_data;

    BYTE_T *buf_pre;

    BYTE_T *buf_send;

    /* 原始資料裝換聲道數所需的變數 */

    INT16_T *buf_chn_r;

    INT16_T *buf_chn_w;

    INT32_T chn_left;

    INT32_T chn_right;

    HISI_INFO(PORT_MODULE_MIC, "(in)");

    while (g_thread_flag)

    {

        if (!g_mic_status)

        {

            usleep(1000);

            continue;

        }

        readlen = mic_pcm_read(g_mic_handle, g_buf_getdata, SAMPLES);

        if (readlen <= 0)

        {

            usleep(10000);

            if (access("/dev/pcmC1D0c", F_OK)!=0 && access("/dev/pcmC0D0c", F_OK)!=0)

            {                

                HISI_INFO(PORT_MODULE_MIC, "(err)can not find MIC decive!");

                if (g_mic_handle != 0 ) 

                    mic_close();

            }

            else

            {

                HISI_INFO(PORT_MODULE_MIC, "(err)not read the data of MIC!");

                if (g_mic_handle == 0 ) 

                {

                    sleep(1); //重新插上後不要馬上開啟

                    mic_open();

                }

            }

            continue;

        }

        #ifdef RECORD_DATA

        fwrite((void *)g_buf_getdata, 1, readlen * g_bits_per_frame / 8, g_original_fp);

        #endif

        /**************************************************************************

         語音處理而言8K取樣率便足夠,若高於8K,丟棄資料使之轉換成8K取樣率

         g_bits_per_frame = g_bits_per_sample * channels

         單聲道一幀的大小:16 * 1 / 8 = 2位元組

         雙聲道一幀的大小:16 * 2 / 8 = 4位元組

         中介軟體只處理單聲道資料,一幀上雙聲道資料轉換為單聲道資料處理方法:

         左聲道資料加上右聲道資料除以2

         取樣率轉換方法:抽樣保留,即16K則每2幀傳一幀上去,32K則每4幀傳一幀上去

         readlen表示一次讀到的幀數,先轉換成單聲道幀,再轉換取樣率

         g_buf_getdata: 存放readi_func讀到的原始資料

         g_buf_transfchn: 原始資料資料轉成單聲道資料後存放到這個buf

         g_buf_transfrate: 取樣率轉換成8K後的資料,該buf資料就是上傳給中介軟體的資料

         **************************************************************************/

        if (1 == chn_mul)

        {

            buf_pre = g_buf_getdata;

        }

        else if (2 == chn_mul)

        {

            buf_chn_r = (INT16_T *)g_buf_getdata;

            buf_chn_w = (INT16_T *)g_buf_transfchn;

            for (i = 0; i <= readlen * g_bits_per_frame / 8; i += 4)

            {

                chn_left = *buf_chn_r++;

                chn_right = *buf_chn_r++;

                *buf_chn_w++ = (INT16_T)((chn_left + chn_right) >> 1);

            }

            buf_pre = g_buf_transfchn;

        }

        if (1 == rate_mul)

        {

            buf_send = buf_pre;

        }

        else

        {

            for (i = 0; i <= readlen * g_bits_per_sample / 8; i += (2 * rate_mul))

            {

                memcpy(g_buf_transfrate + i / 2, buf_pre + i, 2);

            }

            buf_send = g_buf_transfrate;

        }

        g_puting_data = 1;

        mic_lock_buf(PMIC_buf);

        mic_put_loop_buf(PMIC_buf, buf_send, readlen * g_bits_per_frame / 8 /chn_mul/rate_mul);

        mic_unlock_buf(PMIC_buf);

        g_puting_data = 0;

        usleep(100);

    }

    HISI_INFO(PORT_MODULE_MIC, "(out)");

    return IPANEL_OK;

}

/* EOF */

2.Alsa音訊播放

#include <stdio.h>

#include <malloc.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <getopt.h>

#include <fcntl.h>

#include <ctype.h>

#include <errno.h>

#include <limits.h>

#include <time.h>

#include <locale.h>

#include <assert.h>

#include <sys/poll.h>

#include <sys/uio.h>

#include <sys/time.h>

#include <sys/signal.h>

#include <asm/byteorder.h>

#include <pthread.h>

#include "alsa/asoundlib.h"

#include "ipanel_mixer.h"

#include "ipanel_debug.h"

#include "hisi_util.h"

#if 1

/********************************************************************************************************

 *                                        Defines                                                       *

 ********************************************************************************************************/

/* do function and check return */

#define DOFUNC_CHECK(func) \

    do{ \

        ret = func; \

        if ( ret < 0 ) \

        { \

            HISI_ERR(MODULE_PRINT_CAM, "(err)%s failed, ret = %s", #func, errno); \

            goto LAB_ERR; \

        } \

    }while ( 0 )

#define LOOP_BUF_LEN (1024*16)

#define min(x,y) ({ \

    typeof(x) _x = (x); \

    typeof(y) _y = (y); \

    (void) (&_x == &_y);\

    _x < _y ? _x : _y; })

/* ??buffer */

typedef struct {

    pthread_mutex_t mutex;

    BYTE_T buffer[LOOP_BUF_LEN]; 

    UINT32_T in;

    UINT32_T out;

} loop_buf_t;

/********************************************************************************************************

 *                                        Global Variables                                              *

 ********************************************************************************************************/

/********************************************************************************************************

 *                                        Local Variables                                               *

 ********************************************************************************************************/

/* used for DOFUNC_CHECK, save the function name in func_name */

static CHAR_T func_name[64];

static CHAR_T *pfunc;

static snd_pcm_t *g_mixer_handle;

static pthread_t g_mixer_thread = 0;

static UINT32_T g_thread_flag = 0;

static loop_buf_t ring_buf;

static loop_buf_t *PMIXER_buf = &ring_buf;

static UINT32_T g_bits_per_frame;

static UINT32_T g_bits_per_sample;

static INT32_T chn_mul = 1;/* 1:??????; 2:????*/

static INT32_T rate_mul = 1; /* ????8000Hz, 1:8000; 2:16000; 3:24000 ... */

static snd_pcm_uframes_t chunk_size = 0;

/********************************************************************************************************

 *                                        Local Functions Declaring                                     *

 ********************************************************************************************************/

static INT32_T mixer_init_loop_buf(loop_buf_t *buf);

static INT32_T mixer_release_loop_buf(loop_buf_t *buf);

static INT32_T mixer_put_loop_buf(loop_buf_t *buf, BYTE_T *buffer, UINT32_T len);

static INT32_T mixer_get_loop_buf(loop_buf_t *buf, BYTE_T *buffer, UINT32_T len);

static VOID mixer_lock_buf(loop_buf_t *buf);

static VOID mixer_unlock_buf(loop_buf_t *buf);

static INT32_T mixer_get_params(snd_pcm_format_t *format, UINT32_T *channels, UINT32_T *rate);

static INT32_T mixer_set_params(UINT32_T handle);

static IPANEL_AUDIO_MIXER_NOTIFY callBackFunc;

static VOID mixer_usb_task(VOID);

static UINT32_T mixer_open(void);

static INT32_T mixer_set_volume(long vol);

/*********************************************************************

???????? 

??????PCM??????

???????? ??????PCM ?????璞甘????????????????

           ????(?????????????????,??0);

????????????????????IPANEL_DEV_USE_EXCUSIVE????????

          ?????????寫蚩??鞫疾??????????????????矸絞?

          ??IPANEL_DEV_USE_SHARED?????????????俅蚩???????佔實????

          ??????????????????????????????

          ?????????????蚩??????????????????黿?????????????

  ??????????mode?? 使?????;????Func: ????????. 

  ??mixer_send????xmemblk??使??,??通知????,?洗未?????buf??????,

  ????寫 ,????event值為IPANEL_AUDIO_DATA_CONSUMED,??????.

   ???????????? 

??  ?

???? IPANEL_NULL: ???????????; 

???? IPANEL_NULL: ?????璞甘??

************************************************************************/

UINT32_T ipanel_porting_audio_mixer_open(IPANEL_DEV_USE_MODE mode,IPANEL_AUDIO_MIXER_NOTIFY func)

{

    UINT32_T ret;

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

    if (NULL == func)

    {

        HISI_ERR(MODULE_PRINT_CAM, "Call back function is NULL!");

        goto LAB_ERR;

    }

    callBackFunc = func;

    ret = mixer_open();

    if(0 == ret) goto LAB_ERR;

    g_thread_flag = 1;    

    g_mixer_thread = ipanel_porting_task_create("mixer", mixer_usb_task, NULL, 5, 0x8000);    

    if( g_mixer_thread == 0 )    

    {        

        mixer_close();        

 goto LAB_ERR;    

    }

    HISI_INFO(MODULE_PRINT_CAM,"(out)");

    return  g_mixer_handle;

LAB_ERR:

    return IPANEL_NULL;

}

/********************************************************************************************************

????????

??????sound????PCM ????buf ????????????

????????

??????????

handle ?Cmixer?????

pcmblk--  PCM ????????????????

????????????

????????

????IPANEL_OK:??;

IPANEL_ERR: ????????

********************************************************************************************************/

INT32_T ipanel_porting_audio_mixer_memblk_send(UINT32_T handle, IPANEL_XMEMBLK *pcmblk)

{

    INT32_T date_len;

    mixer_lock_buf(PMIXER_buf);

    date_len = mixer_put_loop_buf(PMIXER_buf, pcmblk->pbuf, pcmblk->len);

    printf("Send pcm data to the loop buffer len = %d,pbuf->in=%d,pbuf->out=%d!\n",date_len,PMIXER_buf->in,PMIXER_buf->out);

    mixer_unlock_buf(PMIXER_buf);

    usleep(20000);

    callBackFunc(g_mixer_handle,IPANEL_AUDIO_DATA_CONSUMED,(UINT32_T *)pcmblk);

    return date_len;

}

/************************************************************************************

????

相關推薦

alsa音訊採集播放 (麥克風)

Alsa音訊採集 #include <stdio.h> #include <malloc.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include 

PortAudio採集播放音訊,實現一個雙路混音器

混音,顧名思義,就是把多個音源混合的過程,是一個很常見的應用。這兩天我也做了一個雙路混音器,當然,我沒有做多麼專業的音訊訊號處理,只是一個簡單的混音,調節各路音量,並實現了一些音效處理。主要功能有:採集硬體裝置,讀取wav檔案,播放,混音,音量調節,音訊節奏、音調的調節,wa

iOS 實時音訊採集播放

前言 在iOS中有很多方法可以進行音視訊採集。如 AVCaptureDevice, AudioQueue以及Audio Unit。其中 Audio Unit是最底層的介面,它的優點是功能強大,延遲低; 而缺點是學習成本高,難度大。對於一般的iOS應用程式,AV

仿微信音訊錄入播放

仿微信音訊錄入和播放 lib中匯入so檔案和lib庫 libs檔案下載地址 連結: https://pan.baidu.com/s/1D1q2PV1IQArK79zAt1cfOw 提取碼: f7jg 複製這段內容後開啟百度網盤手機App,操作更方便哦 頁面主類 package

通過網路傳送播放麥克風的聲音

文件及程式碼下載:http://www.dingos.cn/index.php?topic=362.0 介紹 這個例子主要告訴你如何獲取麥克風的聲音且通過UDP方式傳送給另外的計算機。加入雙方都能播放聲音且把麥克風的聲音傳送給對方,這個程式可當作一個P2P的電話。原始碼將

js實現音訊管理播放

不是很熟悉js所以音訊管理和播放看起來真的很複雜的樣子,這個是在msdn看到的。程式碼如下: <!DOCTYPE html> <html> <head> <title>Audio playbackRate Exa

Android音視訊開發初探之AudioRecord與AudioTrack完成音訊採集播放

有陣子沒出文章,接下來爭取每週一更,將沉澱的東西記錄下來,廢話不多說 剛接觸了音視訊方面,趁熱乎記錄一下,歡迎大家指正 接下來會分為一下幾點來介紹: 基礎知識準備 Android MediaRecorder和AudioRecord 與 M

imx6 V4L2視訊採集播放(輸入video0,輸出為video17)

next:         memset(&capture_buf, 0, sizeof(capture_buf));         capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;         capture_buf.memory = V4L2_M

Linux ARM 使用USB麥克風ALSA音訊裝置程式設計

近期有一個專案要用到音訊處理,先是對標準的麥克風輸入裝置進行了測試,後來使用的USB麥克風,在程式設計時遇到了小問題,所以記下筆記。 一、環境 1.系統Linux (Lubuntu) 2.硬體CPU: RK3288(Coretex-A17) 3.USB 麥克風(本篇教程支援Alsa架

Farrago for mac(音訊剪輯現場播放工具)破解教程

Farrago for mac是Mac平臺上一款音訊剪輯工具,Farrago for mac破解版可以在Mac上快速播放聲音效果、音訊效果,同時具備全面的音樂剪輯工具,Mac天空為使用者帶來最新的farrago mac破解版破解教程。 Farrago for mac破解教程 下載好Fa

html,css,js實現音樂播放,含音訊特效歌詞

前端播放器樣例  有需要的小夥伴直接用就行:https://download.csdn.net/download/qq_34042417/10669205 實現思路: 1.載入完頁面後請求等到歌曲,歌詞檔案,要實現歌詞跟歌曲滾動則要求歌詞是lrc格式。 2.對歌詞處理,處理

alsa音訊播放過程中的基本概念

以下為 ALSA-Project/FramesPeriods[1] 學習筆記 1, sample_rate: 即每秒進行多少次取樣,常見的比如 8000、16000、44100和48000等 2, sample_bits: 即每次取樣多少個bit,多是 16bit。其他常見有 24bits、32bits等

Linux ALSA音訊系統之音訊播放

1.amixer設定 a.查詢哪些引數可以控制 #amixer controls numid=2,iface=MIXER,name='DIN source' #通道源選擇 numid=3,iface=MIXER,name='I

麥克風採集播放 (原始碼)

public partial class Form1 : Form { private IAudioPlayer audioPlayer; private IMicrophoneCapturer microphoneCapturer;

簡介錄音播放音訊實現

1.MediaRecorder及MediaPlayer: MediaRecorder類父類是object,位於media包下,是用來錄製音訊和視訊。 下面是錄音模型: 看起來很是複雜的樣子,當然瞭解下流程還是有必要的。至少你知道如果想重新初始化的話,可以直接使用 rese

最簡單的基於FFMPEG+SDL的音訊播放器:拆分-解碼器播放

=====================================================最簡單的基於FFmpeg的音訊播放器系列文章列表:=====================================================本文補充記錄《

音訊實時傳輸播放AMR硬編碼與硬解碼

在Android中我所知道的音訊編解碼有兩種方式: (一)使用AudioRecord採集音訊,用這種方式採集的是未經壓縮的音訊流;用AudioTrack播放實時音訊流。用這兩個類的話,如果需要對音訊進行編解碼,就需要自己移植編解碼庫了,比如可以移植ilbc,speex等開源

ffmpeg錄製usb攝像頭alsa音訊出現ALSA buffer xrun.

參考解決辦法https://stackoverflow.com/questions/28359855/alsa-buffer-xrun-induced-by-low-quality-source-in-ffmpeg-capture 新增-thread_queue_size

HTML5+規範:audio(音訊的錄製播放功能)

   Audio模組用於提供音訊的錄製和播放功能,可呼叫系統的麥克風裝置進行錄音操作,也可呼叫系統的揚聲器裝置播放音訊檔案。通過plus.audio獲取音訊管理物件。 1、常量   ROUTE_SPE

利用JavaScript實現音訊檔案的播放暫停

HTML5 規定了一種通過 audio 元素來包含音訊的標準方法。 audio 元素能夠播放聲音檔案或者音訊流。 注意看,a.paused表示當前音訊的狀態,而音訊的暫停和播放對應的方法分別為pause()和play() ——-(自認為很值得注意的地方 我