原理
最简单的Demo
pthread_t pid;
pthread_mutex_t mutex;
void* __threadHandler(void* args) {
int *obj= (int *)args;
while (!isExit) {
*obj++;
sleep(1);
}
return NULL;
}
void startThread() {
int obj;
pthread_create(&pid, NULL, __threadHandler, (void *) &obj);
}
void stopThread() {
isExit = 0;
}
用多线程处理多个声卡同时录音
#ifndef __AUDIO_RECORD_H__
#define __AUDIO_RECORD_H__
struct recorder {
void *priv;
bool (*init)(struct stream_in *in);
void (*startRecord)(struct stream_in *in);
ssize_t (*obtain)(struct stream_in *in, void *buffer, size_t bytes);
void (*stopRecord)(struct stream_in *in);
void (*destroy)(struct stream_in *in);
bool (*isRecording)(struct stream_in *in);
}
#endif
- 头文件 SimpleMultiRecorder.h
#ifndef __MULTI_CODEC_H__
#define __MULTI_CODEC_H__
#include "AudioQueue.h"
#include <stdlib.h>
#include <audio_utils/resampler.h>
typedef enum micarray_num {
MIC_ARRAY_SINGLE = 1,
MIC_ARRAY_DOUBLE = 2,
MIC_ARRAY_TETRAD = 4,
MIC_ARRAY_SECTUPLE = 6,
}MICARRAY_NUM;
typedef enum pthread_type {
PTHREAD_REF = 0,
PTHREAD_MIC,
PTHREAD_MAIN,
PTHREAD_MAX,
}PTHREAD_TYPE;
struct MultiCodec;
struct pcm_pthread {
struct MultiCodec *os;
int card;
bool pcmRecording;
bool logFileEnable;
bool isCopyLeftToRight;
PTHREAD_TYPE type;
int pcm_size;
struct pcm *pcm;
struct pcm_config *config;
size_t frames_in;
int read_status;
struct resampler_itfe *resampler;
struct resampler_buffer_provider buf_provider;
int16_t *rebuffer;
pthread_t pid;
pthread_mutex_t mutex;
FILE *pcmOrigin;
FILE *pcmResampler;
int queue_size;
char *queue_base;
struct audio_queue_t *queue;
};
struct OUT {
struct MultiCodec *os;
bool isOUTWrite;
bool logFileEnable;
FILE *pcmQueue;
FILE *pcmAPP;
int queue_size;
char *queue_base;
struct audio_queue_t *queue;
};
struct MultiCodec {
struct stream_in *in;
int npthread;
MICARRAY_NUM nmic;
bool isRecording;
bool debugPcm;
bool logFileEnable;
struct OUT *out;
struct pcm_pthread pthread[0];
};
#endif
#define LOG_TAG "SimpleMultiRecorder"
#define LOG_NDEBUG 0
#include "SimpleMultiRecorder.h"
#include "../../audio_hw.h"
#define DEBUG_CARD_ENABLE false
#define DEBUG_RESAMPLER_TO_QUEUE_ENABLE false
#define DEBUG_QUEUE_READ_TO_OUT_ENABLE false
#define DEBUG_OUT_TO_APP_ENABLE false
#define DEBUG_OUT_RESULT_ENABLE false
static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
struct resampler_buffer* buffer)
{
struct pcm_pthread *ppcm;
size_t i;
if (buffer_provider == NULL || buffer == NULL)
return -EINVAL;
ppcm = (struct pcm_pthread *)((char *)buffer_provider -
offsetof(struct pcm_pthread, buf_provider));
if (ppcm->pcm == NULL) {
buffer->raw = NULL;
buffer->frame_count = 0;
ppcm->read_status = -ENODEV;
return -ENODEV;
}
if (ppcm->frames_in == 0) {
ppcm->read_status = pcm_read(ppcm->pcm,
(void*)ppcm->rebuffer, pcm_frames_to_bytes(ppcm->pcm, ppcm->config->period_size));
if (ppcm->read_status != 0) {
ALOGE("get_next_buffer() pcm_read error %d", ppcm->read_status);
buffer->raw = NULL;
buffer->frame_count = 0;
return ppcm->read_status;
}
if (ppcm->logFileEnable) {
fwrite(ppcm->rebuffer, ppcm->pcm_size, 1, ppcm->pcmOrigin);
}
ppcm->frames_in = ppcm->config->period_size;
}
buffer->frame_count = (buffer->frame_count > ppcm->frames_in) ?
ppcm->frames_in : buffer->frame_count;
buffer->i16 = ppcm->rebuffer +
(ppcm->config->period_size - ppcm->frames_in) *
audio_channel_count_from_in_mask(ppcm->os->in->channel);
return ppcm->read_status;
}
static void release_buffer(struct resampler_buffer_provider *buffer_provider,
struct resampler_buffer* buffer)
{
struct pcm_pthread *ppcm;
if (buffer_provider == NULL || buffer == NULL)
return;
ppcm = (struct pcm_pthread *)((char *)buffer_provider -
offsetof(struct pcm_pthread, buf_provider));
ppcm->frames_in -= buffer->frame_count;
}
static ssize_t read_frames(struct pcm_pthread *ppcm, void *buffer, ssize_t frames)
{
ssize_t frames_wr = 0;
size_t frame_size = audio_stream_in_frame_size(&ppcm->os->in->stream);
while (frames_wr < frames) {
size_t frames_rd = frames - frames_wr;
ssize_t frames_offset = frames_wr * frame_size;
if (ppcm->resampler != NULL) {
ppcm->resampler->resample_from_provider(ppcm->resampler,
(int16_t *)((char *)buffer + frames_offset),
&frames_rd);
} else {
struct resampler_buffer buf = {
{ raw : NULL, },
frame_count : frames_rd,
};
get_next_buffer(&ppcm->buf_provider, &buf);
if (buf.raw != NULL) {
memcpy((char *)buffer + frames_offset,
buf.raw,
buf.frame_count * frame_size);
frames_rd = buf.frame_count;
}
release_buffer(&ppcm->buf_provider, &buf);
}
if (ppcm->read_status != 0)
return ppcm->read_status;
frames_wr += frames_rd;
}
return frames_wr;
}
void *SingelRecord(void *args) {
struct pcm_pthread *this = (struct pcm_pthread *)args;
struct stream_in *in = (struct stream_in *)this->os->in;
size_t frames_rq = in->bytes / audio_stream_in_frame_size(&in->stream);
int ret = 0;
char *buffer = NULL;
ALOGE("%s", __FUNCTION__);
this->pcm = pcm_open(this->card, PCM_DEVICE, PCM_IN, this->config);
if (NULL == this->pcm) {
ALOGE(">>>>> pcm[%d] open error!!", this->card);
goto err_pcmopen;
}
this->rebuffer = malloc(this->config->period_size *
this->config->channels * audio_stream_in_frame_size(&in->stream));
if (NULL == this->rebuffer) {
ALOGE(">>>>> malloc rebuffer error!");
goto err_malloc_resamplerbuffer;
}
ALOGE("card[%d], pcm_config->rate:%d, in->requested_rate:%d, in->channel_mask:%d",
this->card, this->config->rate, in->rate, audio_channel_count_from_in_mask(in->channel));
if (in->rate != this->config->rate) {
this->buf_provider.get_next_buffer = get_next_buffer;
this->buf_provider.release_buffer = release_buffer;
ret = create_resampler(this->config->rate ,
in->rate ,
audio_channel_count_from_in_mask(in->channel),
RESAMPLER_QUALITY_DEFAULT,
&this->buf_provider,
&this->resampler);
if (ret != 0) {
goto err_resampler;
}
if (this->resampler) {
this->resampler->reset(this->resampler);
}
this->frames_in = 0;
}
if (this->logFileEnable) {
this->pcmOrigin = fopen("/sdcard/pcmOrigins.pcm", "wb+");
this->pcmResampler = fopen("/sdcard/pcmResamplers.pcm", "wb+");
}
buffer = malloc(this->pcm_size);
if (!buffer) {
goto err_malloc_tmpbuffer;
}
this->pcm_size = in->bytes;
this->pcmRecording = true;
while (this->os->isRecording) {
ret = read_frames(this, buffer, frames_rq);
if (this->logFileEnable && DEBUG_RESAMPLER_TO_QUEUE_ENABLE) {
fwrite(buffer, this->pcm_size, 1, this->pcmResampler);
}
if (ret < 0) {
ALOGE("card[%d] | pcm_read ret = %d", this->card, ret);
}
if (NULL != this->os->queue && !queue_write(this->os->queue, buffer, this->pcm_size)) {
ALOGE("out | queue_write failed. front: %d, rear: %d, cap: %d ",
this->os->queue->front, this->os->queue->rear, this->os->queue->capacity);
}
}
this->pcmRecording = false;
exit:
pthread_mutex_lock(&this->mutex);
free(buffer);
pthread_mutex_unlock(&this->mutex);
err_malloc_tmpbuffer:
if (this->logFileEnable) {
fclose(this->pcmOrigin);
fclose(this->pcmResampler);
}
if (this->resampler) {
release_resampler(this->resampler);
this->resampler = NULL;
}
err_resampler:
free(this->rebuffer);
err_malloc_resamplerbuffer:
pcm_close(this->pcm);
this->pcm = NULL;
pthread_mutex_destroy(&this->mutex);
err_pcmopen:
return NULL;
}
void* MultiSubRecord(void* args) {
struct pcm_pthread *this = (struct pcm_pthread *)args;
struct stream_in *in = (struct stream_in *)this->os->in;
size_t frames_rq = in->bytes / audio_stream_in_frame_size(&in->stream);
int ret = 0;
char *buffer = NULL;
ALOGE("%s", __FUNCTION__);
this->pcm = pcm_open(this->card, PCM_DEVICE, PCM_IN, this->config);
if (NULL == this->pcm) {
ALOGE(">>>>> pcm[%d] open error!!", this->card);
goto err_pcmopen;
}
this->rebuffer = malloc(this->config->period_size *
this->config->channels * audio_stream_in_frame_size(&in->stream));
if (NULL == this->rebuffer) {
ALOGE(">>>>> malloc rebuffer error!");
goto err_malloc_resamplerbuffer;
}
ALOGE("card[%d], pcm_config->rate:%d, in->requested_rate:%d, in->channel_mask:%d",
this->card, this->config->rate, in->rate, audio_channel_count_from_in_mask(in->channel));
if (in->rate != this->config->rate) {
this->buf_provider.get_next_buffer = get_next_buffer;
this->buf_provider.release_buffer = release_buffer;
ret = create_resampler(this->config->rate ,
in->rate ,
audio_channel_count_from_in_mask(in->channel),
RESAMPLER_QUALITY_DEFAULT,
&this->buf_provider,
&this->resampler);
if (ret != 0) {
goto err_resampler;
}
if (this->resampler) {
this->resampler->reset(this->resampler);
}
this->frames_in = 0;
}
if (this->logFileEnable) {
if (this->card == PCM_CARD_ES7243) {
this->pcmOrigin = fopen("/sdcard/pcmOrigin1.pcm", "wb+");
this->pcmResampler = fopen("/sdcard/pcmResampler1.pcm", "wb+");
} else {
this->pcmOrigin = fopen("/sdcard/pcmOrigin0.pcm", "wb+");
this->pcmResampler = fopen("/sdcard/pcmResampler0.pcm", "wb+");
}
}
buffer = malloc(in->bytes);
if (!buffer) {
goto err_malloc_tmpbuffer;
}
this->pcm_size = in->bytes;
this->queue_size = this->pcm_size * 10;
this->queue_base = malloc((sizeof(audio_queue_t) + this->queue_size + 1) * sizeof(char));
if (!this->queue_base) {
goto err_malloc_queuebuffer;
}
this->queue = queue_init(this->queue_base, this->queue_size + 1);
this->pcmRecording = true;
while (this->os->isRecording) {
ret = read_frames(this, buffer, frames_rq);
if (this->logFileEnable && DEBUG_RESAMPLER_TO_QUEUE_ENABLE) {
fwrite(buffer, this->pcm_size, 1, this->pcmResampler);
}
if (ret < 0) {
ALOGE("card[%d] | pcm_read ret = %d", this->card, ret);
}
if (NULL != this->queue && !queue_write(this->queue, buffer, this->pcm_size)) {
ALOGE("card[%d] | queue_write failed. front: %d, rear: %d, cap: %d ",
this->card, this->queue->front, this->queue->rear, this->queue->capacity);
}
}
this->pcmRecording = false;
exit:
pthread_mutex_lock(&this->mutex);
if (NULL != this->queue) {
queue_destroy(this->queue);
this->queue = NULL;
free(this->queue_base);
this->queue_base = NULL;
}
pthread_mutex_unlock(&this->mutex);
err_malloc_queuebuffer:
free(buffer);
err_malloc_tmpbuffer:
if (this->logFileEnable) {
fclose(this->pcmOrigin);
fclose(this->pcmResampler);
}
if (this->resampler) {
release_resampler(this->resampler);
this->resampler = NULL;
}
err_resampler:
free(this->rebuffer);
err_malloc_resamplerbuffer:
pcm_close(this->pcm);
this->pcm = NULL;
pthread_mutex_destroy(&this->mutex);
err_pcmopen:
return NULL;
}
void* MultiMainRecord(void* args) {
struct pcm_pthread *this = (struct pcm_pthread *)args;
struct pcm_pthread *pmic = &this->os->pthread[PTHREAD_MIC];
struct pcm_pthread *pref = &this->os->pthread[PTHREAD_REF];
struct stream_in *in = (struct stream_in *)this->os->in;
int ret = 0;
int i;
int srcFrameIndex, dstFrameIndex = 0;
int realPcmSize = 0;
char *micBuffer = NULL;
char *refBuffer = NULL;
char *realBuffer = NULL;
FILE *pcmFile = NULL;
FILE *pcmMic = NULL, *pcmRef = NULL;
if (this->os->debugPcm) {
pcmFile = fopen("/sdcard/audioraw.pcm", "wb+");
}
if (this->os->logFileEnable) {
pcmMic = fopen("/sdcard/pcm_mic.pcm", "wb+");
pcmRef = fopen("/sdcard/pcm_ref.pcm", "wb+");
}
ALOGE("%s", __FUNCTION__);
realPcmSize = in->bytes * 2 * 2;
micBuffer = malloc(in->bytes * sizeof(char));
refBuffer = malloc(in->bytes * sizeof(char));
realBuffer = malloc(realPcmSize * sizeof(char));
while (this->os->isRecording) {
queue_read(pmic->queue, micBuffer, in->bytes);
queue_read(pref->queue, refBuffer, in->bytes);
memset(realBuffer, 0, realPcmSize);
for (i = 0; i < (in->bytes >> 2); ++i) {
srcFrameIndex = i * 4;
dstFrameIndex = i * 16;
memcpy(realBuffer + dstFrameIndex + 2, micBuffer + srcFrameIndex, 2);
memcpy(realBuffer + dstFrameIndex + 6, micBuffer + srcFrameIndex + 2, 2);
memcpy(realBuffer + dstFrameIndex + 10, refBuffer + srcFrameIndex, 2);
memcpy(realBuffer + dstFrameIndex + 14, refBuffer + srcFrameIndex + 2, 2);
}
if (NULL != this->os->queue && !queue_write(this->os->queue, realBuffer, realPcmSize)) {
ALOGE("out | queue_write failed. front: %d, rear: %d, cap: %d ",
this->os->queue->front, this->os->queue->rear, this->os->queue->capacity);
}
if (this->os->debugPcm && pcmFile) {
fwrite(realBuffer, sizeof(char), realPcmSize, pcmFile);
}
if (this->os->logFileEnable) {
fwrite(micBuffer, sizeof(char), in->bytes, pcmMic);
fwrite(refBuffer, sizeof(char), in->bytes, pcmRef);
}
}
if (this->os->debugPcm && pcmFile) {
fclose(pcmFile);
}
if (this->os->logFileEnable) {
fclose(pcmMic);
fclose(pcmRef);
}
normalexit:
free(micBuffer);
free(refBuffer);
free(realBuffer);
errorexit:
return NULL;
}
static void* (*getThreadHandler(const PTHREAD_TYPE type, const MICARRAY_NUM num))(void* args)
{
switch (type) {
case PTHREAD_MAIN:
return MultiMainRecord;
case PTHREAD_MIC:
case PTHREAD_REF:
return (num != MIC_ARRAY_SINGLE) ? MultiSubRecord : SingelRecord;
case PTHREAD_MAX:
return NULL;
}
return NULL;
}
static int getCard(const PTHREAD_TYPE type)
{
struct pcm *pcm = NULL;
switch (type) {
case PTHREAD_MAIN:
case PTHREAD_MAX:
break;
case PTHREAD_MIC:
return PCM_CARD_ES7243;
case PTHREAD_REF:
return PCM_CARD;
}
return -1;
}
static void setCardConfig(struct pcm_pthread *ppcm)
{
ppcm->pcmRecording = DEBUG_CARD_ENABLE;
switch (ppcm->card) {
case PCM_CARD:
ppcm->isCopyLeftToRight = true;
break;
case PCM_CARD_ES7243:
ppcm->isCopyLeftToRight = false;
break;
case PCM_CARD_MAX:
break;
}
}
static struct OUT *OUT_Init(struct MultiCodec *os)
{
struct OUT *out = malloc(sizeof(struct OUT));
memset(out, 0, sizeof(struct OUT));
out->os = os;
out->queue_size = os->in->bytes * 10;
out->queue_base = malloc((sizeof(audio_queue_t) + out->queue_size + 1) * sizeof(char));
out->queue = queue_init(out->queue_base, out->queue_size + 1);
out->logFileEnable = DEBUG_OUT_RESULT_ENABLE;
if (out->logFileEnable) {
out->pcmQueue = fopen("/sdcard/pcm_queue.pcm", "wb+");
out->pcmAPP = fopen("/sdcard/pcm_app.pcm", "wb+");
}
return out;
}
static int OUT_Destroy(struct OUT *out)
{
if (out->logFileEnable) {
fclose(out->pcmQueue);
fclose(out->pcmAPP);
}
if (NULL != out->queue) {
queue_destroy(out->queue);
out->queue = NULL;
free(out->queue_base);
out->queue_base = NULL;
free(out);
}
return 0;
}
static bool init(struct stream_in *in)
{
int nmic = MIC_ARRAY_DOUBLE;
int npthread = (nmic * 2) - 1;
int ret;
int i = 0;
ALOGE("%s", __FUNCTION__);
struct MultiCodec *os = (struct MultiCodec *)malloc(sizeof(struct MultiCodec) +
npthread * sizeof(struct pcm_pthread));
memset(os, 0, sizeof(struct MultiCodec) + npthread * sizeof(struct pcm_pthread));
os->in = in;
os->nmic = nmic;
os->npthread = npthread;
os->debugPcm = false;
os->logFileEnable = DEBUG_QUEUE_READ_TO_OUT_ENABLE;
os->out = OUT_Init(os);
for (i = 0; i < os->npthread; i++) {
struct pcm_pthread *ppcm = &os->pthread[i];
ppcm->type = i;
ppcm->card = getCard(ppcm->type);
ppcm->logFileEnable = false;
if (ppcm->card >= 0) {
ppcm->config = in->config;
setCardConfig(ppcm);
pthread_mutex_init(&ppcm->mutex, NULL);
}
ppcm->os = os;
}
set_subpriv_data(in->sub, (void *)os);
return true;
}
static void destroy(struct stream_in *in)
{
struct MultiCodec *os = (struct MultiCodec *)get_subpriv_data(in->sub);
ALOGE("%s", __FUNCTION__);
OUT_Destroy(os->out);
free(os);
}
static void startRecord(struct stream_in *in)
{
ALOGE("%s", __FUNCTION__);
int i = 0;
struct MultiCodec *os = (struct MultiCodec *)get_subpriv_data(in->sub);
os->isRecording = true;
for (i = 0; i < os->npthread; i++) {
struct pcm_pthread *ppcm = &os->pthread[i];
pthread_create(&ppcm->pid, NULL, getThreadHandler(ppcm->type, os->nmic), (void *) ppcm);
}
in->dev->input_source = in->source;
in->dev->in_device = in->device;
in->dev->in_channel_mask = in->channel;
}
static void stopRecord(struct stream_in *in)
{
ALOGE("%s", __FUNCTION__);
struct MultiCodec *os = (struct MultiCodec *)get_subpriv_data(in->sub);
os->isRecording = false;
}
static bool isRecording(struct stream_in *in)
{
struct MultiCodec *os = (struct MultiCodec *)get_subpriv_data(in->sub);
return os->isRecording;
}
static ssize_t obtain(struct stream_in *in, void *buffer, size_t bytes)
{
struct MultiCodec *os =
(struct MultiCodec *)get_subpriv_data(in->sub);
struct OUT *out = os->out;
if (NULL != out && NULL != out->queue) {
queue_read(out->queue, buffer, bytes);
if (out->logFileEnable && DEBUG_OUT_TO_APP_ENABLE) {
fwrite(buffer, bytes, 1, out->pcmAPP);
}
}
return 0;
}
struct recorder simple_recorder = {
.init = init,
.destroy = destroy,
.startRecord = startRecord,
.stopRecord = stopRecord,
.isRecording = isRecording,
.obtain = obtain,
};