alsa音频采集和播放

http://blog.csdn.net/liu_xiao_cheng/article/details/43017245

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;

}

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

???????? 

  ???? ipanel_porting_mixer_open ?蚩????????璞甘????同时要?头趴???

?诘拇????????菘椤?

???????? 

  ?????????? 

  mixer ?C???????璞甘?????? 

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

??  ?

IPANEL_OK: ?????谐晒?; 

IPANEL_ERR: ???????

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

INT32_T ipanel_porting_audio_mixer_close(UINT32_T handle)

{

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

    g_thread_flag = 0;    

    ipanel_porting_task_destroy(g_mixer_thread);

    mixer_close();

    HISI_INFO(MODULE_PRINT_CAM,"(out)");

    return IPANEL_OK;

}

 

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

????????

??????sound???????????,???????????煤突?mixer ?璞甘????????????????

????????

    ??????????

        handle ?C???????璞甘??????

        op ?? ????????

        ?ttypedef enum

????{

????    IPANEL_MIXER_SET_VOLUME  = 1,

????    IPANEL_MIXER_CLEAR_BUFFER  = 2,

????    .....

????} IPANEL_MIXER_IOCTL_e;

????arg ?C ???????????????贝???????32 ????值时??

           arg ??????????????????????????VOIP??????使????????.

????op ??arg ??取值?????卤恚?

           OP ARG 说??

            IPANEL_MIXER_CLEAR_BUFFER IPANEL_NULL ???????????????0

            IPANEL_MIXER_SET_VOLUME ?????? ?煞趴?

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

??  ??

IPANEL_OK: ?????谐晒?;

IPANEL_ERR: ????????

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

INT32_T ipanel_porting_audio_mixer_ioctl(UINT32_T handle, IPANEL_MIXER_IOCTL_e op, VOID *arg)

{

    INT32_T i;

 

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

 

    if (handle != g_mixer_handle)

    {

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

        return IPANEL_ERR;

    }

 

    switch(op)

    {

        case IPANEL_MIXER_CLEAR_BUFFER:

        {

            HISI_INFO(MODULE_PRINT_CAM, "IPANEL_MIXER_CLEAR_BUFFER");

            mixer_lock_buf(PMIXER_buf);

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

            PMIXER_buf->in = PMIXER_buf->out = 0;

        mixer_unlock_buf(PMIXER_buf);

        }

        break;

        case IPANEL_MIXER_SET_VOLUME:

        {

            mixer_set_volume(*(long *)arg);

            HISI_INFO(MODULE_PRINT_CAM, "IPANEL_MIXER_SET_VOLUME");

        }

        break;

 

        default:

        {

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

            return IPANEL_ERR;

        }

    }

 

LABEL_OK:

    HISI_INFO(MODULE_PRINT_CAM, "(out)");

    return IPANEL_OK;

}

 

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

 *                                        Local Functions                                               *

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

static UINT32_T mixer_open(void)

{

    INT32_T ret;

    snd_pcm_t *phandle;

    snd_pcm_stream_t stream;

    CHAR_T *pcm_name = "default";

 

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

 

    /* PCM ???????playback */

    stream = SND_PCM_STREAM_PLAYBACK;

 

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

    {

        HISI_INFO(MODULE_PRINT_CAM, "access /dev/pcmC1D0p");

        pcm_name = "hw:1";

    }

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

    {

        HISI_INFO(MODULE_PRINT_CAM, "access /dev/pcmC0D0p");

        pcm_name = "hw:0";

    }

    else

    {

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

        goto LAB_ERR;

    }

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

    g_mixer_handle = (UINT32_T)phandle;

    HISI_INFO(MODULE_PRINT_CAM, "snd_pcm_open, device name %s, handle %d", pcm_name, g_mixer_handle);

 

    mixer_set_params(g_mixer_handle);

    

    mixer_init_loop_buf(PMIXER_buf);

    

    HISI_INFO(MODULE_PRINT_CAM,"(out)");

    return phandle;

LAB_ERR:

    return 0;

}

 

int mixer_close(void)

{

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

    

    snd_pcm_close((snd_pcm_t *)g_mixer_handle);

 

    g_mixer_handle = 0;

    mixer_release_loop_buf(PMIXER_buf);

 

    HISI_INFO(MODULE_PRINT_CAM,"(out)");

    return IPANEL_OK;

 

}

 

static INT32_T mixer_init_loop_buf(loop_buf_t *buf)

{

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

 

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

 

    buf->in = 0;

    buf->out = 0;

 

    pthread_mutex_init(&buf->mutex, NULL);

 

    HISI_INFO(MODULE_PRINT_CAM, "(out)");

    return IPANEL_OK;

}

 

static INT32_T mixer_release_loop_buf(loop_buf_t *buf)

{

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

 

    pthread_mutex_destroy(&buf->mutex);

 

    HISI_INFO(MODULE_PRINT_CAM, "(out)");

    return IPANEL_OK;

}

 

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

{

    UINT32_T num;

 

    HISI_INFO(MODULE_PRINT_CAM, "(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;

    }

 

    HISI_INFO(MODULE_PRINT_CAM, "(out) len = %d", len);

    return len;

}

 

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

{

    UINT32_T num;

 

    HISI_INFO(MODULE_PRINT_CAM, "(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;

    }

 

    HISI_INFO(MODULE_PRINT_CAM, "(out) len = %d", len);

    return len;

}

 

VOID mixer_lock_buf(loop_buf_t *buf)

{

    pthread_mutex_lock(&buf->mutex);

}

 

VOID mixer_unlock_buf(loop_buf_t *buf)

{

    pthread_mutex_unlock(&buf->mutex);

}

 

static INT32_T mixer_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(MODULE_PRINT_CAM, "(in)");

 

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

      ???????? USB MIC??????????ls /dev??????? pcm?????? ALSA ??????????

      ?????遣慰?平台???? USB MIC ?? ALSA??斜恚?

      pcmC0D0p    //C0??card0??D0??device0??p??playback

      pcmC1D0c    //C1??card1??D0??device0??c??capture

 

      硬??????????Format??Channels??Rates?????????

      # cat /proc/asound/card1/stream0

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

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

    {

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

        if (NULL == fp)

        {

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

            goto LAB_ERR;

        }

    }

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

    {

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

        if (NULL == fp)

        {

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

            goto LAB_ERR;

        }

    }

    else

    {

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

        goto LAB_ERR;

    }

 

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

    if (NULL == buf)

    {

        HISI_ERR(MODULE_PRINT_CAM, "buf malloc failed");

        fclose(fp);

        goto LAB_ERR;

    }

 

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

    if (size <= 0)

    {

        HISI_ERR(MODULE_PRINT_CAM, "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(MODULE_PRINT_CAM, "format is SND_PCM_FORMAT_S16_LE");

    }

    else

    {

        HISI_ERR(MODULE_PRINT_CAM, "(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(MODULE_PRINT_CAM, "(err)unkonw channels");

            goto LAB_ERR;

        }

        pt2 = pt+i;

    }

    HISI_INFO(MODULE_PRINT_CAM, "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(MODULE_PRINT_CAM, "Rates:8000");

            *rate = 8000;

            rate_mul = 1;

            break;

        }

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

        {

            HISI_INFO(MODULE_PRINT_CAM, "Rates:16000");

            *rate = 16000;

            rate_mul = 2;

            break;

        }

        pt2 = pt+i;

    }

    if(!pt)

    {

        HISI_INFO(MODULE_PRINT_CAM, "unkonw rate, set default 8000");

        *rate = 8000;

        rate_mul = 1;

    }

 

    free(buf);

    buf = IPANEL_NULL;

    fclose(fp);

 

    HISI_INFO(MODULE_PRINT_CAM, "(out)");

    return IPANEL_OK;

 

LAB_ERR:

    HISI_ERR(MODULE_PRINT_CAM, "(err)");

    return IPANEL_ERR;

}

 

static INT32_T mixer_set_params(UINT32_T handle)

{

    INT32_T ret;

    UINT32_T n;

 

    snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;

    UINT32_T channels = 2;

    UINT32_T rate = 8000;

 

    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 buffer_size;

    snd_pcm_uframes_t start_threshold, stop_threshold;

 

    HISI_INFO(MODULE_PRINT_CAM, "(in)");

 

    phandle = (snd_pcm_t *)handle;

 

    //DOFUNC_CHECK(mixer_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(MODULE_PRINT_CAM, "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));

 

    DOFUNC_CHECK(snd_pcm_prepare(phandle));

 

    g_bits_per_sample = snd_pcm_format_physical_width(format);

    g_bits_per_frame = g_bits_per_sample * channels;

 

    HISI_INFO(MODULE_PRINT_CAM, "(out)");

    return IPANEL_OK;

 

LAB_ERR:

    HISI_ERR(MODULE_PRINT_CAM, "(err)");

    return IPANEL_ERR;

}

 

static VOID mixer_usb_task(VOID)

{

    INT32_T ret;

    INT32_T len;

    snd_pcm_uframes_t frames_to_deliver;

    snd_pcm_uframes_t frameCount;

    BYTE_T buffer[LOOP_BUF_LEN] = {0};

    while (g_thread_flag)

    {

        printf("Start to write pcm data to the device!\n");

        if ((ret = snd_pcm_wait(g_mixer_handle,1000)) < 0)

        {

            snd_pcm_prepare(g_mixer_handle);

            HISI_ERR(MODULE_PRINT_CAM, "Device is not prepared!");

        continue;

  }

        if ((frames_to_deliver = snd_pcm_avail_update(g_mixer_handle)) < 0)

        {

            if (frames_to_deliver == -EPIPE)

         {

      HISI_ERR(MODULE_PRINT_CAM, "An xrun occurred!");

         }

         else if (frames_to_deliver < 0)

         {

              HISI_ERR(MODULE_PRINT_CAM, "Unknown ALSA avail update return value!");

         }

         return;

        }

        frames_to_deliver = frames_to_deliver > chunk_size ? chunk_size : frames_to_deliver;

        printf("frames_to_deliver is %d,chunk_size is %d\n",frames_to_deliver,chunk_size);

 len = frames_to_deliver*g_bits_per_frame/8;

        len = len > LOOP_BUF_LEN ? LOOP_BUF_LEN : len;

        printf("Length is %d\n",len);

 

 mixer_lock_buf(PMIXER_buf);

 ret = mixer_get_loop_buf(PMIXER_buf, buffer, 320);

     if (0 == ret)

     {

        mixer_unlock_buf(PMIXER_buf);

        printf("Read length is 0!\n");

        usleep(20000);

        continue;

     }

 mixer_unlock_buf(PMIXER_buf);

        

 frameCount = ret*8/g_bits_per_frame;

        if (frameCount)

        {

            printf("Write pcm data to the device!\n");

            if ((ret = snd_pcm_writei(g_mixer_handle, buffer, frameCount))<0)

            {

              usleep(2000); 

              if (ret == -EPIPE)

              {

                    /* EPIPE means underrun */

            HISI_ERR(MODULE_PRINT_CAM, "underrun occurred!");

               }

               else if (ret < 0)

               {

                    HISI_ERR(MODULE_PRINT_CAM, "Send PCM date error!");

                }

            }

        }

        else

        {

            HISI_INFO(MODULE_PRINT_CAM, "There is no enough date in the loop buffer!");

            usleep(10000);

        }

    }

}

 

static INT32_T mixer_set_volume(long vol)

{

    snd_mixer_t *mixerFd;

    snd_mixer_elem_t *elem;

    INT32_T result;

    INT32_T minVolume = 0;

    INT32_T maxVolume = 0;

 

    /*?蚩?????*/

    if ((result = snd_mixer_open( &mixerFd, 0)) < 0)

    {

        mixerFd = NULL;

        HISI_ERR(MODULE_PRINT_CAM, "Mixer open error!");

    }

    if ((result = snd_mixer_attach( mixerFd, "hw:0")) < 0)

    {

        snd_mixer_close(mixerFd);

        mixerFd = NULL;

        HISI_ERR(MODULE_PRINT_CAM, "Mixer attach error!");

    }

    if ((result = snd_mixer_selem_register( mixerFd, NULL, NULL)) < 0)

    {

        snd_mixer_close(mixerFd);

        mixerFd = NULL;

        HISI_ERR(MODULE_PRINT_CAM, "Mixer register error!");

    }

    if ((result = snd_mixer_load( mixerFd)) < 0)

    {

        snd_mixer_close(mixerFd);

        mixerFd = NULL;

        HISI_ERR(MODULE_PRINT_CAM, "Mixer load error!");

    }

    for(elem=snd_mixer_first_elem(mixerFd); elem; elem=snd_mixer_elem_next(elem))

    {

        if (snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE && snd_mixer_selem_is_active(elem)) 

        {

            if(strcmp(snd_mixer_selem_get_name(elem),"Master") == 0) 

            {

                if(snd_mixer_selem_has_playback_volume(elem) != 0)

                {

                    snd_mixer_selem_get_playback_volume_range(elem, &minVolume, &maxVolume);

           snd_mixer_selem_set_playback_volume_range(elem, 0, 100);

                    snd_mixer_selem_set_playback_volume_all(elem, vol); 

                }

            }

        }

    }

 

    return 0;

}

 

#endif

 

 

 

3.Linphone中的音频采集和播放部分

#include <alsa/asoundlib.h>

 

 

#include "mediastreamer2/msfilter.h"

#include "mediastreamer2/mssndcard.h"

#if 1//add by jzby  专门起一个线程来处理PCM数据

#define THREADED_VERSION

#else

//#define THREADED_VERSION

#endif

 

//add by jzby

#define PIPE_AUDIO_OUTPUT    /* lxcheng add 2013-11-28 */

 

/*in case of troubles with a particular driver, try incrementing ALSA_PERIOD_SIZE

to 512, 1024, 2048, 4096...

then try incrementing the number of periods*/

#define ALSA_PERIODS 8

//#define ALSA_PERIOD_SIZE 256

#define ALSA_PERIOD_SIZE 1024

 

/*uncomment the following line if you have problems with an alsa driver

having sound quality trouble:*/

/*#define EPIPE_BUGFIX 1*/

 

static MSSndCard * alsa_card_new(int id);

static MSSndCard *alsa_card_duplicate(MSSndCard *obj);

static MSFilter * ms_alsa_read_new(const char *dev);

static MSFilter * ms_alsa_write_new(const char *dev);

 

 

struct _AlsaData{

char *pcmdev;

char *mixdev;

};

 

typedef struct _AlsaData AlsaData;

//#define RECORDFILE

#ifdef RECORDFILE

static int tempFd;

static FILE *rfilefd = NULL;//fopen("/media/alsaRead.pcm","w+");

#endif

 

static void alsa_resume(snd_pcm_t *handle){

int err;

snd_pcm_status_t *status=NULL;

 

snd_pcm_status_alloca(&status);

if ((err=snd_pcm_status(handle,status))!=0){

ms_warning("snd_pcm_status() failed: %s",snd_strerror(err));

return;

}

 

if (snd_pcm_status_get_state(status)==SND_PCM_STATE_SUSPENDED){

ms_warning("Maybe suspended, trying resume");

if ((err=snd_pcm_resume(handle))!=0){

if (err!=EWOULDBLOCK) ms_warning("snd_pcm_resume() failed: %s",snd_strerror(err));

}

}

}

 

static int alsa_set_params(snd_pcm_t *pcm_handle, int rw, int bits, int stereo, int rate)

{

snd_pcm_hw_params_t *hwparams=NULL;

snd_pcm_sw_params_t *swparams=NULL;

int dir;

uint exact_uvalue;

unsigned long exact_ulvalue;

int channels;

int periods=ALSA_PERIODS;

int periodsize=ALSA_PERIOD_SIZE;

int err;

int format;

/* Allocate the snd_pcm_hw_params_t structure on the stack. */

snd_pcm_hw_params_alloca(&hwparams);

/* Init hwparams with full configuration space */

if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {

ms_warning("alsa_set_params: Cannot configure this PCM device.");

return -1;

}

if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {

ms_warning("alsa_set_params: Error setting access.");

return -1;

}

/* Set sample format */

format=SND_PCM_FORMAT_S16;

if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {

ms_warning("alsa_set_params: Error setting format.");

return -1;

}

/* Set number of channels */

if (stereo) channels=2;

else channels=1;

if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {

ms_warning("alsa_set_params: Error setting channels.");

return -1;

}

/* Set sample rate. If the exact rate is not supported */

/* by the hardware, use nearest possible rate.         */ 

exact_uvalue=rate;

dir=0;

if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir))<0){

ms_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err));

return -1;

}

if(exact_uvalue != rate)

{

exact_uvalue = 8000;

snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir);

ms_warning("alsa_set_params: The rate is not supported ==> Using %d Hz instead.", exact_uvalue);

}

/* choose greater period size when rate is high */

periodsize=periodsize*(rate/8000);

/* Set buffer size (in frames). The resulting latency is given by */

/* latency = periodsize * periods / (rate * bytes_per_frame)     */

/* set period size */

exact_ulvalue=periodsize;

dir=0;

if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_ulvalue, &dir) < 0) {

ms_warning("alsa_set_params: Error setting period size.");

return -1;

}

if (dir != 0) {

ms_warning("alsa_set_params: The period size %d is not supported by your hardware.\n "

"==> Using %d instead.", periodsize, (int)exact_ulvalue);

}

ms_warning("alsa_set_params: periodsize:%d Using %d", periodsize, (int)exact_ulvalue);

periodsize=exact_ulvalue;

/* Set number of periods. Periods used to be called fragments. */ 

exact_uvalue=periods;

dir=0;

if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_uvalue, &dir) < 0) {

ms_warning("alsa_set_params: Error setting periods.");

return -1;

}

ms_warning("alsa_set_params: period:%d Using %d", periods, exact_uvalue);

if (dir != 0) {

ms_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n "

"==> Using %d instead.", periods, exact_uvalue);

}

/* Apply HW parameter settings to */

/* PCM device and prepare device  */

if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {

ms_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err));

return -1;

}

/*prepare sw params */

if (rw){

snd_pcm_sw_params_alloca(&swparams);

snd_pcm_sw_params_current(pcm_handle, swparams);

if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){

ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err));

}

if ((err=snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,periodsize*periods ))<0){

ms_warning("alsa_set_params: Error setting stop threshold:%s",snd_strerror(err));

}

if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){

ms_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err));

return -1;

}

}

return 0;

}

 

#ifdef EPIPE_BUGFIX

static void alsa_fill_w (snd_pcm_t *pcm_handle)

{

snd_pcm_hw_params_t *hwparams=NULL;

int channels;

        snd_pcm_uframes_t buffer_size;

int buffer_size_bytes;

void *buffer;

 

/* Allocate the snd_pcm_hw_params_t structure on the stack. */

snd_pcm_hw_params_alloca(&hwparams);

snd_pcm_hw_params_current(pcm_handle, hwparams);

 

/* get channels */

snd_pcm_hw_params_get_channels (hwparams, &channels);

 

/* get buffer size */

snd_pcm_hw_params_get_buffer_size (hwparams, &buffer_size);

 

/* fill half */

buffer_size /= 2;

 

/* allocate buffer assuming 2 bytes per sample */

buffer_size_bytes = buffer_size * channels * 2;

buffer = alloca (buffer_size_bytes);

memset (buffer, 0, buffer_size_bytes);

 

/* write data */

snd_pcm_writei(pcm_handle, buffer, buffer_size);

}

#endif

 

static snd_pcm_t * alsa_open_r(const char *pcmdev,int bits,int stereo,int rate)

{

snd_pcm_t *pcm_handle;

int err;

 

ms_message("alsa_open_r: opening %s at %iHz, bits=%i, stereo=%i",pcmdev,rate,bits,stereo);

 

 

#ifndef THREADED_VERSION

if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) {

ms_warning("alsa_open_r: Error opening PCM device %s",pcmdev );

return NULL;

}

#else

/* want blocking mode for threaded version */

if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,0) < 0) {

ms_warning("alsa_open_r: Error opening PCM device %s",pcmdev );

return NULL;

}

#endif

#if 1//add by jzby 避免反复操作进来是pause状态,即使不起作用也没影响

alsa_resume(pcm_handle);

#endif

{

struct timeval tv1;

struct timeval tv2;

struct timezone tz;

int diff = 0;

err = gettimeofday(&tv1, &tz);

while (1) { 

if (!(alsa_set_params(pcm_handle,0,bits,stereo,rate)<0)){

ms_message("alsa_open_r: Audio params set");

break;

}

if (!gettimeofday(&tv2, &tz) && !err) {

diff = ((tv2.tv_sec - tv1.tv_sec) * 1000000) + (tv2.tv_usec - tv1.tv_usec);

} else {

diff = -1;

}

if ((diff < 0) || (diff > 3000000)) { /* 3 secondes */

ms_error("alsa_open_r: Error setting params for more than 3 seconds");

snd_pcm_close(pcm_handle);

return NULL;

}

ms_warning("alsa_open_r: Error setting params (for %d micros)", diff);

usleep(200000);

}

}

 

err=snd_pcm_start(pcm_handle);

if (err<0){

ms_warning("snd_pcm_start() failed: %s", snd_strerror(err));

}

return pcm_handle;

}

 

static snd_pcm_t * alsa_open_w(const char *pcmdev,int bits,int stereo,int rate)

{

snd_pcm_t *pcm_handle;

 

ms_message("alsa_open_w: opening %s at %iHz, bits=%i, stereo=%i",pcmdev,rate,bits,stereo);

if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {

ms_warning("alsa_open_w: Error opening PCM device %s",pcmdev );

return NULL;

}

alsa_resume(pcm_handle);

{

struct timeval tv1;

struct timeval tv2;

struct timezone tz;

int diff = 0;

int err;

err = gettimeofday(&tv1, &tz);

while (1) { 

if (!(alsa_set_params(pcm_handle,1,bits,stereo,rate)<0)){

ms_message("alsa_open_w: Audio params set");

break;

}

if (!gettimeofday(&tv2, &tz) && !err) {

diff = ((tv2.tv_sec - tv1.tv_sec) * 1000000) + (tv2.tv_usec - tv1.tv_usec);

} else {

diff = -1;

}

if ((diff < 0) || (diff > 3000000)) { /* 3 secondes */

ms_error("alsa_open_w: Error setting params for more than 3 seconds");

snd_pcm_close(pcm_handle);

return NULL;

}

ms_warning("alsa_open_w: Error setting params (for %d micros)", diff);

usleep(200000);

}

}

 

return pcm_handle;

}

 

static int alsa_can_read(snd_pcm_t *dev)

{

snd_pcm_sframes_t avail;

int err;

 

alsa_resume(dev);

avail = snd_pcm_avail_update(dev);

/* A buggy driver does not return an error while being in Xrun */

if (avail >= 0 && snd_pcm_state(dev) == SND_PCM_STATE_XRUN) avail=-EPIPE;

if (avail < 0) {

ms_error("snd_pcm_avail_update: %s", snd_strerror(avail)); // most probably -EPIPE

/* overrun occured, snd_pcm_state() would return SND_PCM_STATE_XRUN

 FIXME: handle other error conditions*/

ms_error("*** alsa_can_read fixup, trying to recover");

snd_pcm_drain(dev); /* Ignore possible error, at least -EAGAIN.*/

err = snd_pcm_recover(dev, avail, 0);

if (err){ 

ms_error("snd_pcm_recover() failed with err %d: %s", err, snd_strerror(err));

return -1;

}

err = snd_pcm_start(dev);

if (err){ 

ms_error("snd_pcm_start() failed with err %d: %s", err, snd_strerror(err)); 

return -1; 

}

ms_message("Recovery done");

}

return avail;

}

 

 

static int alsa_read(snd_pcm_t *handle,unsigned char *buf,int nsamples)

{

int err;

err=snd_pcm_readi(handle,buf,nsamples);

if (err<0) {

ms_warning("alsa_read: snd_pcm_readi() returned %i",err);

if (err==-EPIPE){

snd_pcm_prepare(handle);

err=snd_pcm_readi(handle,buf,nsamples);

if (err<0) ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err));

}else if (err==-ESTRPIPE){

alsa_resume(handle);

}else if (err!=-EWOULDBLOCK){

ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err));

}

}else if (err==0){

ms_warning("alsa_read: snd_pcm_readi() returned 0");

}

return err;

}

 

 

static int alsa_write(snd_pcm_t *handle,unsigned char *buf,int nsamples)

{

int err;

if ((err=snd_pcm_writei(handle,buf,nsamples))<0){

if (err==-EPIPE){

snd_pcm_prepare(handle);

#ifdef EPIPE_BUGFIX

alsa_fill_w (handle);

#endif

err=snd_pcm_writei(handle,buf,nsamples);

if (err<0) ms_warning("alsa_card_write: Error writing sound buffer (nsamples=%i):%s",nsamples,snd_strerror(err));

}else if (err==-ESTRPIPE){

alsa_resume(handle);

}else if (err!=-EWOULDBLOCK){

ms_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err));

}

}else if (err!=nsamples) {

ms_debug("Only %i samples written instead of %i",err,nsamples);

}

return err;

}

 

 

static snd_mixer_t *alsa_mixer_open(const char *mixdev){

snd_mixer_t *mixer=NULL;

int err;

err=snd_mixer_open(&mixer,0);

if (err<0){

ms_warning("Could not open alsa mixer: %s",snd_strerror(err));

return NULL;

}

if ((err = snd_mixer_attach (mixer, mixdev)) < 0){

ms_warning("Could not attach mixer to card: %s",snd_strerror(err));

snd_mixer_close(mixer);

return NULL;

}

if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){

ms_warning("snd_mixer_selem_register: %s",snd_strerror(err));

snd_mixer_close(mixer);

return NULL;

}

if ((err = snd_mixer_load (mixer)) < 0){

ms_warning("snd_mixer_load: %s",snd_strerror(err));

snd_mixer_close(mixer);

return NULL;

}

return mixer;

}

 

static void alsa_mixer_close(snd_mixer_t *mix){

snd_mixer_close(mix);

}

 

typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction;

 

static int get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){

long value=0;

const char *elemname;

snd_mixer_elem_t *elem;

int err;

long sndMixerPMin=0;

long sndMixerPMax=0;

long newvol=0;

elem=snd_mixer_first_elem(mixer);

while (elem!=NULL){

elemname=snd_mixer_selem_get_name(elem);

//ms_message("Found alsa mixer element %s.",elemname);

if (strcmp(elemname,name)==0){

switch (action){

case CAPTURE:

if (snd_mixer_selem_has_capture_volume(elem)){

snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax);

err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol);

newvol-=sndMixerPMin;

value=(100*newvol)/(sndMixerPMax-sndMixerPMin);

if (err<0) ms_warning("Could not get capture volume for %s:%s",name,snd_strerror(err));

//else ms_message("Successfully get capture level for %s.",elemname);

break;

}

break;

case PLAYBACK:

if (snd_mixer_selem_has_playback_volume(elem)){

snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);

err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol);

newvol-=sndMixerPMin;

value=(100*newvol)/(sndMixerPMax-sndMixerPMin);

if (err<0) ms_warning("Could not get playback volume for %s:%s",name,snd_strerror(err));

//else ms_message("Successfully get playback level for %s.",elemname);

break;

}

break;

case CAPTURE_SWITCH:

break;

case PLAYBACK_SWITCH:

 

break;

}

}

elem=snd_mixer_elem_next(elem);

}

return value;

}

 

 

static void set_mixer_element(snd_mixer_t *mixer,const char *name, int level,MixerAction action){

const char *elemname;

snd_mixer_elem_t *elem;

long sndMixerPMin=0;

long sndMixerPMax=0;

long newvol=0;

elem=snd_mixer_first_elem(mixer);

while (elem!=NULL){

elemname=snd_mixer_selem_get_name(elem);

//ms_message("Found alsa mixer element %s.",elemname);

if (strcmp(elemname,name)==0){

switch(action){

case CAPTURE:

if (snd_mixer_selem_has_capture_volume(elem)){

snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax);

newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;

snd_mixer_selem_set_capture_volume_all(elem,newvol);

//ms_message("Successfully set capture level for %s.",elemname);

return;

}

break;

case PLAYBACK:

if (snd_mixer_selem_has_playback_volume(elem)){

snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);

newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;

snd_mixer_selem_set_playback_volume_all(elem,newvol);

//ms_message("Successfully set playback level for %s.",elemname);

return;

}

break;

case CAPTURE_SWITCH:

if (snd_mixer_selem_has_capture_switch(elem)){

snd_mixer_selem_set_capture_switch_all(elem,level);

//ms_message("Successfully set capture switch for %s.",elemname);

}

break;

case PLAYBACK_SWITCH:

if (snd_mixer_selem_has_playback_switch(elem)){

snd_mixer_selem_set_playback_switch_all(elem,level);

//ms_message("Successfully set capture switch for %s.",elemname);

}

break;

 

}

}

elem=snd_mixer_elem_next(elem);

}

 

return ;

}

 

 

static void alsa_card_set_level(MSSndCard *obj,MSSndCardMixerElem e,int a)

{

snd_mixer_t *mixer;

AlsaData *ad=(AlsaData*)obj->data;

mixer=alsa_mixer_open(ad->mixdev);

if (mixer==NULL) return ;

switch(e){

case MS_SND_CARD_MASTER:

set_mixer_element(mixer,"Master",a,PLAYBACK);

break;

case MS_SND_CARD_CAPTURE:

set_mixer_element(mixer,"Capture",a,CAPTURE);

break;

case MS_SND_CARD_PLAYBACK:

set_mixer_element(mixer,"PCM",a,PLAYBACK);

break;

default:

ms_warning("alsa_card_set_level: unsupported command.");

}

alsa_mixer_close(mixer);

}

 

static int alsa_card_get_level(MSSndCard *obj, MSSndCardMixerElem e)

{

snd_mixer_t *mixer;

AlsaData *ad=(AlsaData*)obj->data;

int value = -1;

mixer=alsa_mixer_open(ad->mixdev);

if (mixer==NULL) return 0;

switch(e){

case MS_SND_CARD_MASTER:

value=get_mixer_element(mixer,"Master",PLAYBACK);

break;

case MS_SND_CARD_CAPTURE:

value=get_mixer_element(mixer,"Capture",CAPTURE);

break;

case MS_SND_CARD_PLAYBACK:

value=get_mixer_element(mixer,"PCM",PLAYBACK);

break;

default:

ms_warning("alsa_card_set_level: unsupported command.");

}

alsa_mixer_close(mixer);

return value;

}

 

static void alsa_card_set_source(MSSndCard *obj,MSSndCardCapture source)

{

snd_mixer_t *mixer;

AlsaData *ad=(AlsaData*)obj->data;

mixer=alsa_mixer_open(ad->mixdev);

if (mixer==NULL) return;

switch (source){

case MS_SND_CARD_MIC:

set_mixer_element(mixer,"Mic",1,CAPTURE_SWITCH);

set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);

break;

case MS_SND_CARD_LINE:

set_mixer_element(mixer,"Line",1,CAPTURE_SWITCH);

set_mixer_element(mixer,"Capture",1,CAPTURE_SWITCH);

break;

}

alsa_mixer_close(mixer);

}

 

static MSFilter *alsa_card_create_reader(MSSndCard *card)

{

AlsaData *ad=(AlsaData*)card->data;

MSFilter *f=ms_alsa_read_new(ad->pcmdev);

return f;

}

 

static MSFilter *alsa_card_create_writer(MSSndCard *card)

{

AlsaData *ad=(AlsaData*)card->data;

MSFilter *f=ms_alsa_write_new(ad->pcmdev);

return f;

}

 

 

static void alsa_card_init(MSSndCard *obj){

AlsaData *ad=ms_new0(AlsaData,1);

obj->data=ad;

}

 

static void alsa_card_uninit(MSSndCard *obj){

AlsaData *ad=(AlsaData*)obj->data;

if (ad->pcmdev!=NULL) ms_free(ad->pcmdev);

if (ad->mixdev!=NULL) ms_free(ad->mixdev);

ms_free(ad);

}

 

static void alsa_card_detect(MSSndCardManager *m){

int i;

for (i=-1;i<10;i++){

MSSndCard *card=alsa_card_new(i);

if (card!=NULL)

ms_snd_card_manager_add_card(m,card);

}

}

 

MSSndCardDesc alsa_card_desc={

.driver_type="ALSA",

.detect=alsa_card_detect,

.init=alsa_card_init,

.set_level=alsa_card_set_level,

.get_level=alsa_card_get_level,

.set_capture=alsa_card_set_source,

.set_control=NULL,

.get_control=NULL,

.create_reader=alsa_card_create_reader,

.create_writer=alsa_card_create_writer,

.uninit=alsa_card_uninit,

.duplicate=alsa_card_duplicate

};

 

static MSSndCard *alsa_card_duplicate(MSSndCard *obj){

MSSndCard *card=ms_snd_card_new(&alsa_card_desc);

AlsaData* dcard=(AlsaData*)card->data;

AlsaData* dobj=(AlsaData*)obj->data;

card->name=ms_strdup(obj->name);

card->id=ms_strdup(obj->id);

dcard->pcmdev=ms_strdup(dobj->pcmdev);

dcard->mixdev=ms_strdup(dobj->mixdev);

return card;

}

 

MSSndCard * ms_alsa_card_new_custom(const char *pcmdev, const char *mixdev){

MSSndCard * obj;

AlsaData *ad;

obj=ms_snd_card_new(&alsa_card_desc);

ad=(AlsaData*)obj->data;

obj->name=ms_strdup(pcmdev);

ad->pcmdev=ms_strdup(pcmdev);

ad->mixdev=ms_strdup(mixdev);

return obj;

}

 

static unsigned int get_card_capabilities(const char *devname){

snd_pcm_t *pcm_handle;

unsigned int ret=0;

if (snd_pcm_open(&pcm_handle,devname,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK)==0) {

ret|=MS_SND_CARD_CAP_CAPTURE;

snd_pcm_close(pcm_handle);

}

if (snd_pcm_open(&pcm_handle,devname,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK)==0) {

ret|=MS_SND_CARD_CAP_PLAYBACK;

snd_pcm_close(pcm_handle);

}

return ret;

}

 

static MSSndCard * alsa_card_new(int id)

{

MSSndCard * obj;

char *name=NULL;

AlsaData *ad;

int err;

if (id!=-1){

err=snd_card_get_name(id,&name);

if (err<0) {

return NULL;

}

}

obj=ms_snd_card_new(&alsa_card_desc);

ad=(AlsaData*)obj->data;

if (id==-1) {

/* the default pcm device */

obj->name=ms_strdup("default device");

ad->pcmdev=ms_strdup("default");

ad->mixdev=ms_strdup("default");

}else{

/* remove trailing spaces from card name */

char *pos1, *pos2;

pos1=ms_strdup(name);

pos2=pos1+strlen(pos1)-1;

for (; pos2>pos1 && *pos2==' '; pos2--) *pos2='\0';

obj->name=pos1;

ad->pcmdev=ms_strdup_printf("default:%i",id);

ad->mixdev=ms_strdup_printf("default:%i",id);

{

snd_mixer_t *mixer;

mixer = alsa_mixer_open(ad->mixdev);

if (mixer==NULL) {

ms_free(ad->mixdev);

ad->mixdev=ms_strdup_printf("hw:%i",id);

} else {

alsa_mixer_close(mixer);

}

}

}

/*check card capabilities: */

obj->capabilities=get_card_capabilities(ad->pcmdev);

if (obj->capabilities==0){

ms_warning("Strange, sound card %s does not seems to be capable of anything, retrying with plughw...",obj->name);

/*retry with plughw: this workarounds an alsa bug*/

ms_free(ad->pcmdev);

ad->pcmdev=ms_strdup_printf("plughw:%i",id);

obj->capabilities=get_card_capabilities(ad->pcmdev);

if (obj->capabilities==0){

ms_warning("Strange, sound card %s seems totally unusable.",obj->name);

}

}

free(name);

/*ms_message("alsa device %s found",obj->name);*/

return obj;

}

 

struct _AlsaReadData{

char *pcmdev;

snd_pcm_t *handle;

int rate;

int nchannels;

 

#ifdef THREADED_VERSION

ms_thread_t thread;

ms_mutex_t mutex;

MSBufferizer * bufferizer;

bool_t read_started;

bool_t write_started;

#endif

};

 

typedef struct _AlsaReadData AlsaReadData;

void alsa_read_init(MSFilter *obj){

AlsaReadData *ad=ms_new(AlsaReadData,1);

ad->pcmdev=NULL;

ad->handle=NULL;

ad->rate=8000;

ad->nchannels=1;

obj->data=ad;

#ifdef RECORDFILE

rfilefd = fopen("/media/alsaRead.pcm","w+");

#endif

#ifdef THREADED_VERSION

ad->read_started=FALSE;

ad->write_started=FALSE;

ad->bufferizer=ms_bufferizer_new();

ms_mutex_init(&ad->mutex,NULL);

ad->thread=0;

#endif

}

 

#ifdef THREADED_VERSION

 

static void * alsa_write_thread(void *p){

AlsaReadData *ad=(AlsaReadData*)p;

int samples=(160*ad->rate)/8000;

int err;

int count=0;

mblk_t *om=NULL;

struct timeval timeout;

 

if (ad->handle==NULL && ad->pcmdev!=NULL)

{

usleep(50*1000);

ad->handle = alsa_open_r(ad->pcmdev,16,ad->nchannels==2, ad->rate); 

}

if (ad->handle==NULL) return NULL;

 

while (ad->read_started)

  {

#if 1//add by jzby 函数参数个数原始bug

    count = alsa_can_read(ad->handle);

#else

    count = alsa_can_read(ad->handle,samples);

#endif

    if (count==24)

      { /* keep this value for this driver */ }

    else if (count<=0)

      {

count = samples;

      }

    else if (count>0)

      {

//ms_warning("%i count", count);

//count = samples;

      }

 

    int size=count*2;

    om=allocb(size,0);

 

    if ((err=alsa_read(ad->handle,om->b_wptr,count))<=0)

      {

ms_warning("nothing to read");

//ms_warning("Fail to read samples %i", count);

freemsg(om); /* leak fixed */

continue;

      }

    //ms_warning(" read %i", err);

    

    size=err*2;

    om->b_wptr+=size;

 

    ms_mutex_lock(&ad->mutex);

    ms_bufferizer_put(ad->bufferizer,om);

    ms_mutex_unlock(&ad->mutex);

 

    if (count==24)

      {

timeout.tv_sec = 0;

timeout.tv_usec = 2000;

select(0, 0, NULL, NULL, &timeout );

      }

    else

      {

/* select will be less active than locking on "read" */

timeout.tv_sec = 0;

timeout.tv_usec = 5000;

select(0, 0, NULL, NULL, &timeout );

      }

  }

 

if (ad->handle!=NULL) snd_pcm_close(ad->handle);

ad->handle=NULL;

return NULL;

}

 

static void alsa_start_r(AlsaReadData *d){

if (d->read_started==FALSE){

d->read_started=TRUE;

ms_thread_create(&d->thread,NULL,alsa_write_thread,d);

}else d->read_started=TRUE;

}

 

static void alsa_stop_r(AlsaReadData *d){

d->read_started=FALSE;

if (d->thread!=0)

  {

    ms_thread_join(d->thread,NULL);

    d->thread=0;

  }

}

#endif

 

#ifdef THREADED_VERSION

void alsa_read_preprocess(MSFilter *obj){

AlsaReadData *ad=(AlsaReadData*)obj->data;

alsa_start_r(ad);

}

#endif

 

void alsa_read_postprocess(MSFilter *obj){

AlsaReadData *ad=(AlsaReadData*)obj->data;

#ifdef THREADED_VERSION

alsa_stop_r(ad);

#endif

if (ad->handle!=NULL) snd_pcm_close(ad->handle);

#ifdef RECORDFILE

fclose(rfilefd);

#endif

ad->handle=NULL;

 

}

 

void alsa_read_uninit(MSFilter *obj){

AlsaReadData *ad=(AlsaReadData*)obj->data;

#ifdef THREADED_VERSION

alsa_stop_r(ad);

#endif

if (ad->pcmdev!=NULL) ms_free(ad->pcmdev);

if (ad->handle!=NULL) snd_pcm_close(ad->handle);

#ifdef THREADED_VERSION

ms_bufferizer_destroy(ad->bufferizer);

ms_mutex_destroy(&ad->mutex);

#endif

ms_free(ad);

}

 

#ifndef THREADED_VERSION

void alsa_read_process(MSFilter *obj){

AlsaReadData *ad=(AlsaReadData*)obj->data;

int samples=(128*ad->rate)/8000;

int err;

mblk_t *om=NULL;

if (ad->handle==NULL && ad->pcmdev!=NULL){

ad->handle=alsa_open_r(ad->pcmdev,16,ad->nchannels==2,ad->rate);

}

if (ad->handle==NULL) return;

while (alsa_can_read(ad->handle)>=samples){

  

int size=samples*2*ad->nchannels;

om=allocb(size,0);

if ((err=alsa_read(ad->handle,om->b_wptr,samples))<=0) {

ms_warning("Fail to read samples");

freemsg(om);

return;

}

size=err*2*ad->nchannels;

om->b_wptr+=size;

/*ms_message("alsa_read_process: Outputing %i bytes",size);*/

ms_queue_put(obj->outputs[0],om);

}

}

#endif

 

#ifdef THREADED_VERSION

void alsa_read_process(MSFilter *obj){

AlsaReadData *ad=(AlsaReadData*)obj->data;

mblk_t *om=NULL;

int samples=(160*ad->rate)/8000;

int size=samples*2*ad->nchannels;

int ret = 0;

    

ms_mutex_lock(&ad->mutex);

while (ms_bufferizer_get_avail(ad->bufferizer)>=size){

  

  om=allocb(size,0);

  ms_bufferizer_read(ad->bufferizer,om->b_wptr,size);   

  om->b_wptr+=size;

  /*ms_message("alsa_read_process: Outputing %i bytes",size);*/

  ms_queue_put(obj->outputs[0],om);

#ifdef RECORDFILE

  ret = fwrite(om->b_wptr-size, 1, size, rfilefd);

      if (ret != size)

      {

          printf("fwrite err, write size=%d, slclen=%d\n", ret, size);

      }

#endif

}

ms_mutex_unlock(&ad->mutex);

}

#endif

 

static int alsa_read_get_sample_rate(MSFilter *obj, void *param){

AlsaReadData *ad=(AlsaReadData*)obj->data;

*((int*)param)=ad->rate;

return 0;

}

 

static int alsa_read_set_sample_rate(MSFilter *obj, void *param){

AlsaReadData *ad=(AlsaReadData*)obj->data;

ad->rate=*((int*)param);

return 0;

}

 

static int alsa_read_set_nchannels(MSFilter *obj, void *param){

AlsaReadData *ad=(AlsaReadData*)obj->data;

ad->nchannels=*((int*)param);

return 0;

}

 

MSFilterMethod alsa_read_methods[]={

{MS_FILTER_GET_SAMPLE_RATE, alsa_read_get_sample_rate},

{MS_FILTER_SET_SAMPLE_RATE, alsa_read_set_sample_rate},

{MS_FILTER_SET_NCHANNELS, alsa_read_set_nchannels},

{0,NULL}

};

 

MSFilterDesc alsa_read_desc={

.id=MS_ALSA_READ_ID,

.name="MSAlsaRead",

.text=N_("Alsa sound source"),

.category=MS_FILTER_OTHER,

.ninputs=0,

.noutputs=1,

.init=alsa_read_init,

#ifdef THREADED_VERSION

.preprocess=alsa_read_preprocess,

#endif

.process=alsa_read_process,

.postprocess=alsa_read_postprocess,

.uninit=alsa_read_uninit,

.methods=alsa_read_methods

};

 

static MSFilter * ms_alsa_read_new(const char *dev){

MSFilter *f=ms_filter_new_from_desc(&alsa_read_desc);

AlsaReadData *ad=(AlsaReadData*)f->data;

ad->pcmdev=ms_strdup(dev);

return f;

}

 

typedef struct _AlsaReadData AlsaWriteData;

 

#ifdef PIPE_AUDIO_OUTPUT

static void pipe_write_preprocess(MSFilter *f);

#endif

void alsa_write_init(MSFilter *obj){

AlsaWriteData *ad=ms_new(AlsaWriteData,1);

ad->pcmdev=NULL;

ad->handle=NULL;

ad->rate=8000;

ad->nchannels=1;

obj->data=ad;

#ifdef PIPE_AUDIO_OUTPUT

//pipe_write_preprocess(obj);

#endif

}

 

void alsa_write_postprocess(MSFilter *obj){

AlsaReadData *ad=(AlsaReadData*)obj->data;

if (ad->handle!=NULL) snd_pcm_close(ad->handle);

ad->handle=NULL;

}

 

void alsa_write_uninit(MSFilter *obj){

AlsaWriteData *ad=(AlsaWriteData*)obj->data;

if (ad->pcmdev!=NULL) ms_free(ad->pcmdev);

if (ad->handle!=NULL) snd_pcm_close(ad->handle);

ms_free(ad);

}

 

static int alsa_write_get_sample_rate(MSFilter *obj, void *data){

AlsaWriteData *ad=(AlsaWriteData*)obj->data;

*((int*)data)=ad->rate;

return 0;

}

 

int alsa_write_set_sample_rate(MSFilter *obj, void *data){

int *rate=(int*)data;

AlsaWriteData *ad=(AlsaWriteData*)obj->data;

ad->rate=*rate;

return 0;

}

 

int alsa_write_set_nchannels(MSFilter *obj, void *data){

int *n=(int*)data;

AlsaWriteData *ad=(AlsaWriteData*)obj->data;

ad->nchannels=*n;

return 0;

}

 

void alsa_write_process(MSFilter *obj){

AlsaWriteData *ad=(AlsaWriteData*)obj->data;

mblk_t *im=NULL;

int size;

int samples;

int err;

if (ad->handle==NULL && ad->pcmdev!=NULL){

ad->handle=alsa_open_w(ad->pcmdev,16,ad->nchannels==2,ad->rate);

#ifdef EPIPE_BUGFIX

alsa_fill_w (ad->pcmdev);

#endif

}

if (ad->handle==NULL) {

ms_queue_flush(obj->inputs[0]);

return;

}

while ((im=ms_queue_get(obj->inputs[0]))!=NULL){

while((size=im->b_wptr-im->b_rptr)>0){

samples=size/(2*ad->nchannels);

err=alsa_write(ad->handle,im->b_rptr,samples);

if (err>0) {

im->b_rptr+=err*(2*ad->nchannels);

}

else break;

}

freemsg(im);

}

}

 

#ifdef PIPE_AUDIO_OUTPUT

 

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <linux/un.h>

 

typedef union

{

    int word;

    struct

    {

        unsigned char Byte0;

        unsigned char Byte1;

        unsigned char Byte2;

        unsigned char Byte3;

    } byte;

} INT4BYTE;

 

 

static char *m_audio_path = NULL;

static int pipe_write_data(const char *path, const unsigned char *ptr, const int size)

{

    int len;

    int sock = -1;

int i;

    struct sockaddr_un sa;

 

    if((!path) || (!ptr) || (size <0)) {

        printf("error audio_pipe_write_data input path %p, ptr %p, size %d\n", path, ptr, size);

        return -1;

    }

    

    sock=socket(AF_UNIX,SOCK_STREAM,0);

    if(sock == -1) {

        printf("%s,%d socket is error\n", __FILE__, __LINE__);

        return -1;

    }

    sa.sun_family=AF_UNIX;

    strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);

for(i = 0; i < 10; i++){

     if (!connect(sock,(struct sockaddr*)&sa,sizeof(sa))){

         break;

     }

printf("%s, %d, connecting to audio_server....%dsec\n", __FILE__, __LINE__, i);

sleep(1);

}

 

if(i == 10){

close(sock);

         printf("%s,%d connect to audio_server error\n", __FILE__, __LINE__);

         return -1;

}

    len = write(sock, ptr, size);

 

    if( len == -1) {

        printf("%s,%d write  is error\n", __FILE__, __LINE__);

    }

 

    close(sock);

 

    return len;

 

}

 

static void pipe_write_preprocess(MSFilter *f){

    AlsaWriteData *ad=(AlsaWriteData*)f->data;

    unsigned char buf[10];

    INT4BYTE tmp;

    bool_t stereo = ((ad->nchannels)==2);

 

#ifdef RECORDFILE

    tempFd = open("/mnt/tmpWriteData.pcm", O_WRONLY | O_CREAT | O_TRUNC);

    if(tempFd < 0){

        printf("open /mnt/tmpWriteData.pcm failed: %s",strerror(errno));

    }

#endif

 

    m_audio_path = strdup("/tmp/remote-audio");

 

    buf[0] = 0xFF;

    buf[1] = stereo +1;

    tmp.word = 16;

    buf[2] = tmp.byte.Byte0;

    buf[3] = tmp.byte.Byte1;

    buf[4] = tmp.byte.Byte2;

    buf[5] = tmp.byte.Byte3;

    tmp.word = ad->rate;

    buf[6] = tmp.byte.Byte0;

    buf[7] = tmp.byte.Byte1;

    buf[8] = tmp.byte.Byte2;

    buf[9] = tmp.byte.Byte3;

    if(pipe_write_data(m_audio_path, buf, sizeof(buf)) == -1 ) {

        printf("%s,%d, audio_pipe_write_data is error\n", __FILE__, __LINE__);

    }

}

 

 

static void pipe_write_postprocess(MSFilter *f){

 

free(m_audio_path);

m_audio_path = NULL;

#ifdef RECORDFILE

    close(tempFd);

#endif

 

}

 

static void pipe_write_process(MSFilter *f){

mblk_t *im = NULL;

    int size;

 

while((im=ms_queue_get(f->inputs[0]))!=NULL){

        size=im->b_wptr-im->b_rptr;

        if(size > 0) {

#ifdef BLUE_TEST

if(use_bluetooth_flag)

{

samples=size/(2*ad->nchannels);   //im->b_rptr

pthread_mutex_lock(&use_bluetooth_mutex);

if(use_bluetooth_play)

{

samples=size/(2*ad->nchannels);  

err=alsa_write(ad->handle,im->b_rptr,samples);

printf("\e[34m [ %s | %d ] Write 2 \e[0m\n", __FUNCTION__, __LINE__);

}

use_bluetooth_play = FALSE;

pthread_mutex_unlock(&use_bluetooth_mutex);

if (err>0) {

im->b_rptr+=err*(2*ad->nchannels);

}

else break;

 

}

else

#endif 

{

if(pipe_write_data(m_audio_path, im->b_rptr, size) == -1 ) {

                printf("%s,%d, audio_pipe_write_data is error\n", __FILE__, __LINE__);

            }

#ifdef RECORDFILE

write(tempFd,im->b_rptr,size);

#endif

}

freemsg(im);

        }

}

}

 

#endif

 

MSFilterMethod alsa_write_methods[]={

{MS_FILTER_GET_SAMPLE_RATE, alsa_write_get_sample_rate},

{MS_FILTER_SET_SAMPLE_RATE, alsa_write_set_sample_rate},

{MS_FILTER_SET_NCHANNELS, alsa_write_set_nchannels},

{0,NULL}

};

 

#ifdef PIPE_AUDIO_OUTPUT

MSFilterDesc alsa_write_desc={

.id=MS_ALSA_WRITE_ID,

.name="MSAlsaWrite",

.text=N_("Alsa sound output"),

.category=MS_FILTER_OTHER,

.ninputs=1,

.noutputs=0,

.init=alsa_write_init,

.preprocess=pipe_write_preprocess,

.process=pipe_write_process,

.postprocess=pipe_write_postprocess,

.uninit=alsa_write_uninit,

.methods=alsa_write_methods

};

 

#else

MSFilterDesc alsa_write_desc={

.id=MS_ALSA_WRITE_ID,

.name="MSAlsaWrite",

.text=N_("Alsa sound output"),

.category=MS_FILTER_OTHER,

.ninputs=1,

.noutputs=0,

.init=alsa_write_init,

.process=alsa_write_process,

.postprocess=alsa_write_postprocess,

.uninit=alsa_write_uninit,

.methods=alsa_write_methods

};

#endif

 

static MSFilter * ms_alsa_write_new(const char *dev){

MSFilter *f=ms_filter_new_from_desc(&alsa_write_desc);

AlsaWriteData *ad=(AlsaWriteData*)f->data;

ad->pcmdev=ms_strdup(dev);

return f;

}

 

 

MS_FILTER_DESC_EXPORT(alsa_write_desc)

 

MS_FILTER_DESC_EXPORT(alsa_read_desc)


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值