C语言 - 多线程(thread)设计

原理

最简单的Demo

// thread 变量 
pthread_t pid;
pthread_mutex_t mutex;

// 1. 定义线程处理函数
void* __threadHandler(void* args) {
	int *obj= (int *)args;
	while (!isExit) {
	    *obj++;
	    sleep(1);
	}
    
    return NULL;
}

// 2. 启动线程
void startThread() {
    int obj;
    pthread_create(&pid, NULL, __threadHandler, (void *) &obj);    
}

// 3. 停止线程
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 // __AUDIO_RECORD_H__
  • 头文件 SimpleMultiRecorder.h
#ifndef __MULTI_CODEC_H__
#define __MULTI_CODEC_H__

// Modify Tower Tips: https://blog.csdn.net/qq_33443989/article/details/105157865
#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;

	// state & info
	int card;
	bool pcmRecording;
	bool logFileEnable;
	bool isCopyLeftToRight;
	PTHREAD_TYPE type;
	
    int pcm_size;
	struct pcm *pcm;	
	struct pcm_config *config;

	// resampler
	size_t frames_in;
	int read_status;
    struct resampler_itfe *resampler;
	struct resampler_buffer_provider buf_provider;
	int16_t *rebuffer;  // 重采样的缓存区.
	
	// thread
	pthread_t pid;
	pthread_mutex_t mutex;

	FILE *pcmOrigin;
	FILE *pcmResampler;

	// queue
	int queue_size;
	char *queue_base;
	struct audio_queue_t *queue;
};

struct OUT {
	struct MultiCodec *os;
	
	bool isOUTWrite;
	bool logFileEnable;
	FILE *pcmQueue;
	FILE *pcmAPP;
	
    // output
	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 // __MULTI_CODEC_H__
  • 头文件
#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;
        }

		// save origin audio
		if (ppcm->logFileEnable) {
			fwrite(ppcm->rebuffer, ppcm->pcm_size, 1, ppcm->pcmOrigin);
		}
		
        ppcm->frames_in = ppcm->config->period_size;

		/* MONO => Stereo 暂时用不到. 
        // Do stereo to mono conversion in place by discarding right channel 
        if (ppcm->os->in->channel == AUDIO_CHANNEL_IN_MONO) {
            for (i = 0; i < ppcm->frames_in; i++)
                ppcm->rebuffer[i] = ppcm->rebuffer[i * 2];
        }
        */
    }
	
	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);
        }
		
        /* in->read_status is updated by getNextBuffer() also called by
         * in->resampler->e() */
        if (ppcm->read_status != 0)
            return ppcm->read_status;

        frames_wr += frames_rd;
    }
	
    return frames_wr;
}

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Apdate MIC_ARRAY_SINGLE.
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;
	}
	
	// buffer
	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;
    }

	// resampler
	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 /* src rate */,
                               in->rate /* dst rate */,
                               audio_channel_count_from_in_mask(in->channel),
                               RESAMPLER_QUALITY_DEFAULT,
                               &this->buf_provider,
                               &this->resampler);
        if (ret != 0) {
            goto err_resampler;
        }

		/* if no supported sample rate is available, use the 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;
	}
	
	// buffer
	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;
	}

	// resampler
	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 /* src rate */,
                               in->rate /* dst rate */,
                               audio_channel_count_from_in_mask(in->channel),
                               RESAMPLER_QUALITY_DEFAULT,
                               &this->buf_provider,
                               &this->resampler);
        if (ret != 0) {
            goto err_resampler;
        }
		
		/* if no supported sample rate is available, use the 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+");
		}
    }
	
	// queue
	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__);
	// ATTH: wait subrecord start!.
	//while (!pmic->pcmRecording || !pref->pcmRecording) {
	//	sleep(1);
	//	continue;
	//}
	
	realPcmSize = in->bytes * 2 * 2;//需要32位的
	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;   //2个通道16位
            dstFrameIndex = i * 16;  //4个通道32位
            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) 
{
    // debug swtich
	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)
{
    // out
	struct OUT *out = malloc(sizeof(struct OUT));
	memset(out, 0, sizeof(struct OUT));
	
	// out queue is privder AudioReocrd origin audio.
	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));
	
	// micnum pthread
	// 1      1
	// 2      3
	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;
		
		// Mainthread is not need reality card.
		if (ppcm->card >= 0) {
			// pcm config
			ppcm->config = in->config;
			setCardConfig(ppcm);
		
			// mutex
			pthread_mutex_init(&ppcm->mutex, NULL);
		}
		
		// pthread
		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,
};

发布了53 篇原创文章 · 获赞 19 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_33443989/article/details/105157840