使用pjsip实现一个录音机和播放器

2023-04-25 17:56:59 浏览数 (2)

录音机:录制为PCM文件

代码语言:javascript复制
//broadcast_record.c

/*

录制wav,之后编码,再通过组播发送出去

组播接收wav, 解码?播放wav

*/
#include <pjmedia-audiodev/audiodev.h> 
#include <pjmedia.h>
#include <pjlib.h>
#include <pjlib-util.h>

#include "broadcast_app.h"

#define THIS_FILE	"broadcast_record.c"
static volatile pj_pool_t *pool = NULL;
static pjmedia_aud_param param;
static volatile pjmedia_aud_stream *strm = NULL;
static unsigned playback_lat = 20;//PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
static unsigned capture_lat = 20;

static volatile RecordCallback recordCallback = NULL;

int stop_record(void)
{ 
    recordCallback = NULL;
    if (strm) {
		pjmedia_aud_stream_stop(strm);
		pjmedia_aud_stream_destroy(strm);
    } 
    if (pool){
		pj_pool_release(pool);

    }
    strm = NULL;
    pool = NULL;
	return 0;
}

static pj_status_t wav_rec_cb(void *user_data, pjmedia_frame *frame)
{
	//回调函数
    //return pjmedia_port_put_frame((pjmedia_port*)user_data, frame);
    pj_int16_t *pcm_in   = (pj_int16_t*)frame->buf;

    //编码?
    //发送?
    if (recordCallback != NULL){
        recordCallback(user_data, pcm_in, (int)frame->size, frame->timestamp.u32.lo);
    } 

	return 0;
}

/*
sample_rate:16000
channel:1
*/
int start_record(int sample_rate, int channel, void *user_data, RecordCallback callback)
{  
    pj_status_t status;

    //first stop 
    stop_record();

    pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "wav",
			  1000, 1000, NULL);
 
    status = pjmedia_aud_dev_default_param(0, &param);
    if (status != PJ_SUCCESS) {
		printf("pjmedia_aud_dev_default_param()", status);
		goto on_return;
    }

    param.dir = PJMEDIA_DIR_CAPTURE;
    param.clock_rate = sample_rate;
    param.samples_per_frame = (sample_rate/1000)*10*channel;//*2
    param.channel_count = channel;
    param.bits_per_sample = 16;
    /* Latency settings */
    param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 
		    PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
    param.input_latency_ms = capture_lat;
    param.output_latency_ms = playback_lat;

    if (strm) {
		pjmedia_aud_stream_stop(strm);
		pjmedia_aud_stream_destroy(strm);
    } 
    status = pjmedia_aud_stream_create(&param, &wav_rec_cb, NULL, user_data,
				       &strm);
    if (status != PJ_SUCCESS) {
		printf("Error opening the sound device", status);
		goto on_failed;
    }

    status = pjmedia_aud_stream_start(strm);
    if (status != PJ_SUCCESS) {
		printf("Error starting the sound device", status);
		goto on_failed;
    }

    //增加回调函数
    recordCallback = callback;

    PJ_LOG(3,(THIS_FILE, "Recording started"));
    goto on_return;

on_failed:
    if (strm) {
		pjmedia_aud_stream_stop(strm);
		pjmedia_aud_stream_destroy(strm);
    } 
    if (pool){
		pj_pool_release(pool);

    }
on_return:
	return 0;
}


播放器:播放PCM音频;

代码语言:javascript复制
//broadcast_play.c


#include <pjmedia-audiodev/audiodev.h> 
#include <pjmedia.h>
#include <pjlib.h>
#include <pjlib-util.h>
#include "broadcast_app.h"

#define THIS_FILE	"broadcast_play.c"

static volatile pj_pool_t *pool = NULL;
static pjmedia_aud_param param;
static volatile pjmedia_aud_stream *strm = NULL;
static unsigned playback_lat = 20;//PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
static unsigned capture_lat = 20;//PJMEDIA_SND_DEFAULT_REC_LATENCY;


static volatile RecordCallback playCallback = NULL;

static pj_status_t wav_play_cb(void *user_data, pjmedia_frame *frame)
{
    //return pjmedia_port_get_frame((pjmedia_port*)user_data, frame);
    if (playCallback != NULL){
        playCallback(user_data, frame->buf, (int)frame->size, frame->timestamp.u32.lo);
    }
    return 0;
}

int stop_play(void){
    playCallback = NULL;
    if (strm) {
		pjmedia_aud_stream_stop(strm);
		pjmedia_aud_stream_destroy(strm); 
    } 
    if (pool){
		pj_pool_release(pool); 
    }
    strm = NULL;
    pool = NULL;
    printf("stop_play() endrn");
	return 0;
}

/*
sample_rate:16000
channel:1
user_data:回调的用户对象
callback:回调函数
*/
int start_play(int sample_rate, int channel, void *user_data, PlayCallback callback)
{
    pj_status_t status;
    //first stop 
    stop_record();
 

    pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "play",
			  1000, 1000, NULL); 


    status = pjmedia_aud_dev_default_param(0, &param);
    if (status != PJ_SUCCESS) {
		printf("pjmedia_aud_dev_default_param()", status);
		goto on_return;
    }
 
    param.dir = PJMEDIA_DIR_PLAYBACK;
    param.clock_rate = sample_rate;
    param.samples_per_frame = (sample_rate/1000)*10*channel;//320;*2
    param.channel_count = channel;
    param.bits_per_sample = 16;
    /* Latency settings */
    param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 
		    PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
    param.input_latency_ms = capture_lat;
    param.output_latency_ms = playback_lat;

    status = pjmedia_aud_stream_create(&param, NULL, &wav_play_cb, user_data,
				       &strm);
    if (status != PJ_SUCCESS) {
		printf("Error opening the sound device", status);
		goto on_failed;
    }

    status = pjmedia_aud_stream_start(strm);
    if (status != PJ_SUCCESS) {
		printf("Error starting the sound device", status);
		goto on_failed;
    }
    playCallback = callback;

    PJ_LOG(3,(THIS_FILE, "play started,strm:x",strm));
    goto on_return;

on_failed:
    if (strm) {
		pjmedia_aud_stream_stop(strm);
		pjmedia_aud_stream_destroy(strm);
    } 
    if (pool){
		pj_pool_release(pool);

    }
on_return:
	return 0;
}

broadcast_app.h

代码语言:javascript复制
//broadcast_app.h
#ifndef __BROADCAST_APP__
#define __BROADCAST_APP__

#include <unistd.h>
 
#ifdef __cplusplus
extern "C"{
#endif

typedef int (*PlayCallback)(void *user_data,uint8_t *rawData, int len, uint32_t timestamp);

typedef int (*RecordCallback)(void *user_data,uint16_t *rawData, int len, uint32_t timestamp);

int start_play(int sample_rate, int channel,void *user_data, PlayCallback callback);
int stop_play(void);

int start_record(int sample_rate, int channel,void *user_data, RecordCallback callback);
int stop_record(void);




#ifdef __cplusplus
}
#endif 

#endif//__BROADCAST_APP__

调用:

代码语言:javascript复制

#define RECORD_SAMPLE_RATE    16000
#define RECORD_SAMPLE_CHANNEL 2

static int RecordCallbackFunc(void *user_data,uint16_t *rawData, int len, uint32_t timestamp){
//写wav文件
}


//set mic callback
start_record(RECORD_SAMPLE_RATE, RECORD_SAMPLE_CHANNEL, NULL, RecordCallbackFunc);
	


static int PlayCallbackFunc(void *user_data,uint8_t *rawData, int len, uint32_t timestamp){
//从缓冲区中读PCM数据,然后写到rawData中
	struct ringbuf ringitem ;
	int itemlen  = ringget(&ringitem);
	if (itemlen > 0 && rawData != NULL){
		int copy_len = itemlen;
		if (itemlen > len){
			copy_len = len;	
		}
		memcpy(rawData, ringitem.buffer, copy_len);
	}
	return 0;
}

	
start_play(RECORD_SAMPLE_RATE, RECORD_SAMPLE_CHANNEL, NULL, PlayCallbackFunc);

0 人点赞