前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用pjsip实现一个录音机和播放器

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

原创
作者头像
呱牛笔记
修改2023-04-25 17:56:59
1.1K0
修改2023-04-25 17:56:59
举报
文章被收录于专栏:呱牛笔记

录音机:录制为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() end\r\n");
	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:%08x",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);

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档