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_func的data
g_send_fp儲存傳給中介軟體的資料,ipanel_porting_mic_read的data
***************************************************************/
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可強制轉換成對應資料型別。
op和arg的取值關係見下表:
+-----------------------+-----------------------------------+--------------------+
|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表示card0,D0表示device0,p表示playback
pcmC1D0c //C1表示card1,D0表示device0,c表示capture
硬體資訊不能定死,Format、Channels、Rates要在裝置資訊檔案中讀取
# 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音訊採集
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include
混音,顧名思義,就是把多個音源混合的過程,是一個很常見的應用。這兩天我也做了一個雙路混音器,當然,我沒有做多麼專業的音訊訊號處理,只是一個簡單的混音,調節各路音量,並實現了一些音效處理。主要功能有:採集硬體裝置,讀取wav檔案,播放,混音,音量調節,音訊節奏、音調的調節,wa
前言
在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所以音訊管理和播放看起來真的很複雜的樣子,這個是在msdn看到的。程式碼如下:
<!DOCTYPE html>
<html>
<head>
<title>Audio playbackRate Exa
有陣子沒出文章,接下來爭取每週一更,將沉澱的東西記錄下來,廢話不多說
剛接觸了音視訊方面,趁熱乎記錄一下,歡迎大家指正
接下來會分為一下幾點來介紹:
基礎知識準備
Android MediaRecorder和AudioRecord 與 M next:
memset(&capture_buf, 0, sizeof(capture_buf));
capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
capture_buf.memory = V4L2_M
近期有一個專案要用到音訊處理,先是對標準的麥克風輸入裝置進行了測試,後來使用的USB麥克風,在程式設計時遇到了小問題,所以記下筆記。
一、環境
1.系統Linux (Lubuntu)
2.硬體CPU: RK3288(Coretex-A17)
3.USB 麥克風(本篇教程支援Alsa架
Farrago for mac是Mac平臺上一款音訊剪輯工具,Farrago for mac破解版可以在Mac上快速播放聲音效果、音訊效果,同時具備全面的音樂剪輯工具,Mac天空為使用者帶來最新的farrago mac破解版破解教程。
Farrago for mac破解教程
下載好Fa
前端播放器樣例
有需要的小夥伴直接用就行:https://download.csdn.net/download/qq_34042417/10669205
實現思路:
1.載入完頁面後請求等到歌曲,歌詞檔案,要實現歌詞跟歌曲滾動則要求歌詞是lrc格式。
2.對歌詞處理,處理 以下為 ALSA-Project/FramesPeriods[1] 學習筆記
1, sample_rate: 即每秒進行多少次取樣,常見的比如 8000、16000、44100和48000等 2, sample_bits: 即每次取樣多少個bit,多是 16bit。其他常見有 24bits、32bits等
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的音訊播放器系列文章列表:=====================================================本文補充記錄《
在Android中我所知道的音訊編解碼有兩種方式:
(一)使用AudioRecord採集音訊,用這種方式採集的是未經壓縮的音訊流;用AudioTrack播放實時音訊流。用這兩個類的話,如果需要對音訊進行編解碼,就需要自己移植編解碼庫了,比如可以移植ilbc,speex等開源
參考解決辦法https://stackoverflow.com/questions/28359855/alsa-buffer-xrun-induced-by-low-quality-source-in-ffmpeg-capture
新增-thread_queue_size
Audio模組用於提供音訊的錄製和播放功能,可呼叫系統的麥克風裝置進行錄音操作,也可呼叫系統的揚聲器裝置播放音訊檔案。通過plus.audio獲取音訊管理物件。
1、常量
ROUTE_SPE
HTML5 規定了一種通過 audio 元素來包含音訊的標準方法。
audio 元素能夠播放聲音檔案或者音訊流。
注意看,a.paused表示當前音訊的狀態,而音訊的暫停和播放對應的方法分別為pause()和play() ——-(自認為很值得注意的地方 我 相關推薦
alsa音訊採集和播放 (麥克風)
PortAudio採集和播放音訊,實現一個雙路混音器
iOS 實時音訊採集與播放
仿微信音訊錄入和播放
通過網路傳送和播放麥克風的聲音
js實現音訊管理和播放
Android音視訊開發初探之AudioRecord與AudioTrack完成音訊採集與播放
imx6 V4L2視訊採集和播放(輸入video0,輸出為video17)
Linux ARM 使用USB麥克風ALSA音訊裝置程式設計
Farrago for mac(音訊剪輯和現場播放工具)破解教程
html,css,js實現音樂播放,含音訊特效和歌詞
alsa音訊播放過程中的基本概念
Linux ALSA音訊系統之音訊播放
麥克風採集與播放 (原始碼)
簡介錄音和播放音訊實現
最簡單的基於FFMPEG+SDL的音訊播放器:拆分-解碼器和播放器
音訊實時傳輸和播放AMR硬編碼與硬解碼
ffmpeg錄製usb攝像頭和alsa音訊出現ALSA buffer xrun.
HTML5+規範:audio(音訊的錄製和播放功能)
利用JavaScript實現音訊檔案的播放和暫停