版本信息:
编辑器:DevEco Studio NEXT Beta1 Version: 5.0.3.810
编辑器内置 SDK:5.0.0
编译工具:commandline-tools-linux-x64-5.0.3.800
alsa: alsa-lib-1.1.3
pjsip: pjproject-2.13.1
我编译了PJSIP和ALSA,编译过程没遇到问题,但是在运行时PJSIP和ALSA都找不到声卡驱动,导致无法呼叫,我不清楚是我编译的问题还是设备的问题,我查了很多资料,都是让我安装ALSA,并重新编译PJSIP,我都编译好了,但是还是没效果,希望可以给些提示,下面是错信息:
pjsua_call.c !Making call with acc #0 to sip:95795403#18872910795@siptest.v-call.cn
pjsua_aud.c .Set sound device: capture=-1, playback=-2, mode=0, use_default_settings=0
pjsua_aud.c ..Error retrieving default audio device parameters: Unable to find default audio device (PJMEDIA_EAUD_NODEFDEV) [status=420006]
pjsua_media.c .Call 0: deinitializing media..
call.cpp pjsua_call_make_call(acc.getId(), &pj_dst_uri, param.p_opt, this, param.p_msg_data, &id) error: Unable to find default audio device (PJMEDIA_EAUD_NODEFDEV) (status=420006) [../src/pjsua2/call.cpp:701]
在注册发起时,可以看到PJSIP确实已经使用了ALSA,但是依然找不到设备“ALSA driver found 0 devices”
sip_endpoint.c .Module "mod-100rel" registered
sip_endpoint.c .Module "mod-pjsua" registered
sip_endpoint.c .Module "mod-invite" registered
alsa_dev.c ..ALSA driver found 0 devices
alsa_dev.c ..ALSA initialized
pjlib ..select() I/O Queue created (0x5b0c387c28)
sip_endpoint.c .Module "mod-evsub" registered
我在编译ALSA时使用的是默认设备路径,是不是跟这个有关系?
checking for ALSA device file directory... /dev/snd/
checking for aload* device file directory... /dev/
OH应用层不支持alsa,应用无法调用alsa的接口的。音频模块OH当前有ohaudio/opensl模块,建议用户自行适配OH的ohaudio。OHAUDIO介绍文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/using-ohaudio-for-playback-V5.OHAUDIO的demo实例:https://gitee.com/harmonyos_samples/audio-native
好的,感谢! 我看第三方库里有alsa-lib,我还以为支持呢
我没看太懂你的 AudioRendererOnWriteData 方法里是要干嘛?注册一个pj_thread线程?我的实现方式是在 AudioRendererOnWriteData 方法这种从缓存队列中读取buffer数据,并填充到 void *buffer 里,实现音频输出,下面是我的实现
int32_t AudioRendererOnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t bufferLen) {
(void) renderer;
(void) userData;
renderMtx.lock();
uint8_t *dest = (uint8_t *)buffer;
size_t index = 0;
size_t len = bufferLen > renderQueue.size() ? renderQueue.size() : bufferLen;
while (!renderQueue.empty() && index < len) {
dest[index++] = renderQueue.front();
renderQueue.pop();
}
renderMtx.unlock();
return 0;
}
您好,非常感谢回复,想实现的目标是在鸿蒙next版本的虚拟机上可以使用pjsip来实现voip业务。
开始,也遇到了找不到音频设备,然后按照上面给的建议“需用户自行适配OH的ohaudio”,在pjsip里面根据ohaudio demo逻辑在pjsip里添加ohaudio模块,并重新编译;
随后,使用dev创建c++工程并使用编译后的库文件,在调用makecall后出现
“LastFatalMessage:Assertion failed: !"Calling pjlib from unknown/external thread. You must " "register external threads with pj_thread_register() " "before calling any pjlib functions." (../src/pj/os_core_unix.c: pj_thread_this: 844)”,
Fault thread info:
Tid:6719, Name:OS_AudioWriteCB
这样的提示,看到“OS_AudioWriteCB”这样提示, 对应的是OH_AudioRenderer_OnWriteData = AudioRendererOnWriteData,ohaudio play回调函数,然后根据pjsip库提示在AudioRendererOnWriteData回调函数里加入了“pj_thread_register("media", desc, &pthread);}”,并重新编译,但没有效果然后仍有上面的错误提示,回调函数AudioRendererOnWriteData里面不添加任何业务代码,也有上面的错误提示,若设置成OH_AudioRenderer_OnWriteData = NULL则没有上面的错误提示,但媒体数据就不能使用了,所以想问一下对于这样的错误有什么建议
OH_AudioRenderer_Callbacks rendererCallbacks;
rendererCallbacks.OH_AudioRenderer_OnWriteData = AudioRendererOnWriteData;
下面是主要代码
#include <stdbool.h>
#include <ohaudio/native_audiocapturer.h>
#include <ohaudio/native_audiorenderer.h>
#include <ohaudio/native_audiostreambuilder.h>
#include <ohaudio/native_audiostream_base.h>
const int GLOBAL_RESMGR = 0xFF00;
const char *TAG = "[Sample_audio]";
int32_t g_samplingRate = 48000;
int32_t g_channelCount = 1;//2
static OH_AudioCapturer *audioCapturer;
static OH_AudioRenderer *audioRenderer;
static OH_AudioStreamBuilder *builder;
static OH_AudioStreamBuilder *rendererBuilder;
static struct ohaudio_aud_stream *mStream;
#define W_SLBufferQueueItf SLOHBufferQueueItf
#define W_SLBufferQueueState SLOHBufferQueueState
#define W_SL_IID_BUFFERQUEUE SL_IID_OH_BUFFERQUEUE
#define THIS_FILE "ohaduio_dev.c"
#define DRIVER_NAME "OhAudio"
#define NUM_BUFFERS 3
static int32_t AudioRendererOnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t bufferLen) {
try{
int status;
if (mStream->play_thread_initialized == 0 || !pj_thread_is_registered())
{
pj_bzero(mStream->play_thread_desc, sizeof(pj_thread_desc));
status = pj_thread_register("ohaudio_play", mStream->play_thread_desc,
&mStream->play_thread);
mStream->play_thread_initialized = 1;
}
}catch(...){
PJ_LOG(4, (THIS_FILE, "opensl AudioRendererOnWriteData Error "));
}
return 0;
}
static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t bufferLen) {
char name[16];
pthread_getname_np(pthread_self(), name, sizeof(name));
PJ_LOG(4, (THIS_FILE, "opensl Recorder thread started %s",name));
try{
int status;
if (mStream->rec_thread_initialized == 0 || !pj_thread_is_registered())
{
// pj_bzero(mStream->rec_thread_desc, sizeof(pj_thread_desc));
status = pj_thread_register("ohaudio_rec", mStream->rec_thread_desc,
&mStream->rec_thread);
PJ_UNUSED_ARG(status); /* Unused for now.. */
mStream->rec_thread_initialized = 1;
}
return 0;
}
/* Init Android audio driver. */
extern "C" pjmedia_aud_dev_factory* pjmedia_ohaudio_factory(pj_pool_factory *pf)
{
struct ohaudio_aud_factory *f;
pj_pool_t *pool;
pool = pj_pool_create(pf, "opensles", 256, 256, NULL);
f = PJ_POOL_ZALLOC_T(pool, struct ohaudio_aud_factory);
f->pf = pf;
f->pool = pool;
f->base.op = &ohaudio_op;
return &f->base;
}
/* API: Destroy factory */
static pj_status_t ohaudio_destroy(pjmedia_aud_dev_factory *f)
{
//录音
if (audioCapturer) {
OH_AudioStreamBuilder_Destroy(builder);
OH_AudioCapturer_Release(audioCapturer);
audioCapturer = NULL;
builder = NULL;
}
//播放
if (audioRenderer) {
OH_AudioStreamBuilder_Destroy(rendererBuilder);
OH_AudioRenderer_Release(audioRenderer);
audioRenderer = NULL;
rendererBuilder = NULL;
}
pool = pa->pool;
pa->pool = NULL;
pj_pool_release(pool);
return PJ_SUCCESS;
}
/* API: create stream */
static pj_status_t ohaudio_create_stream(pjmedia_aud_dev_factory *f,
const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_aud_strm)
{
if (audioRenderer) {
OH_AudioRenderer_Release(audioRenderer);
OH_AudioStreamBuilder_Destroy(rendererBuilder);
audioRenderer = NULL;
rendererBuilder = NULL;
}
OH_AudioStream_Type type = AUDIOSTREAM_TYPE_RENDERER;
OH_AudioStreamBuilder_Create(&rendererBuilder, type);
// set params and callbacks
OH_AudioStreamBuilder_SetSamplingRate(rendererBuilder, g_samplingRate);//g_samplingRate
OH_AudioStreamBuilder_SetChannelCount(rendererBuilder, g_channelCount);
OH_AudioStreamBuilder_SetLatencyMode(rendererBuilder, AUDIOSTREAM_LATENCY_MODE_NORMAL);
OH_AudioStreamBuilder_SetFrameSizeInCallback(rendererBuilder, 2500);
OH_AudioStreamBuilder_SetSampleFormat(rendererBuilder, AUDIOSTREAM_SAMPLE_S16LE);
OH_AudioStreamBuilder_SetEncodingType(rendererBuilder, AUDIOSTREAM_ENCODING_TYPE_RAW);
// 关键参数,仅OHAudio支持,根据音频用途设置,系统会根据此参数实现音频策略自适应
OH_AudioStreamBuilder_SetRendererInfo(rendererBuilder, AUDIOSTREAM_USAGE_MOVIE);
OH_AudioRenderer_Callbacks rendererCallbacks;
rendererCallbacks.OH_AudioRenderer_OnWriteData = AudioRendererOnWriteData;//AudioRendererOnWriteData
rendererCallbacks.OH_AudioRenderer_OnStreamEvent = NULL;
rendererCallbacks.OH_AudioRenderer_OnInterruptEvent = NULL;
rendererCallbacks.OH_AudioRenderer_OnError = NULL;
OH_AudioStreamBuilder_SetRendererCallback(rendererBuilder, rendererCallbacks, user_data);
// create OH_AudioRenderer
OH_AudioStreamBuilder_GenerateRenderer(rendererBuilder, &audioRenderer);
if (audioCapturer) {
OH_AudioCapturer_Release(audioCapturer);
OH_AudioStreamBuilder_Destroy(builder);
audioCapturer = NULL;
builder = NULL;
}
OH_AudioStream_Type ohType = AUDIOSTREAM_TYPE_CAPTURER;
OH_AudioStreamBuilder_Create(&builder, ohType);
// 2. set params and callbacks
OH_AudioStreamBuilder_SetSamplingRate(builder, g_samplingRate);//g_samplingRate
OH_AudioStreamBuilder_SetChannelCount(builder, g_channelCount);
OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_NORMAL);
OH_AudioCapturer_Callbacks callbacks;
callbacks.OH_AudioCapturer_OnReadData = AudioCapturerOnReadData;//AudioCapturerOnReadData
callbacks.OH_AudioCapturer_OnStreamEvent = NULL;
callbacks.OH_AudioCapturer_OnInterruptEvent = NULL;
callbacks.OH_AudioCapturer_OnError = NULL;
OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, NULL);
// 3. create OH_AudioCapturer
OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer);
/* Done */
mStream->base.op = &ohaudio_strm_op;
*p_aud_strm = &mStream->base;
return PJ_SUCCESS;
}
/* API: start stream. */
static pj_status_t strm_start(pjmedia_aud_stream *s)
{
mStream->quit_flag = 0;
OH_AudioRenderer_Start(audioRenderer);
OH_AudioCapturer_Start(audioCapturer);
return PJ_SUCCESS;
}
#endif /* PJMEDIA_AUDIO_DEV_HAS_OPENSL */
@zhong-luping 您好,按照audio-native demo进行适配
OH_AudioRenderer_Callbacks rendererCallbacks;
rendererCallbacks.OH_AudioRenderer_OnWriteData = AudioRendererOnWriteData;
rendererCallbacks.OH_AudioRenderer_OnError = nullptr;
rendererCallbacks.OH_AudioRenderer_OnInterruptEvent = nullptr;
rendererCallbacks.OH_AudioRenderer_OnStreamEvent = nullptr;
OH_AudioStreamBuilder_SetRendererCallback(rendererBuilder, rendererCallbacks, nullptr);
在虚拟机API12 上运行出现
Reason:Signal:SIGABRT(SI_TKILL)@0x01317b4f0000190d from:6413:20020047
LastFatalMessage:Assertion failed: !"Calling pjlib from unknown/external thread. You must " "register external threads with pj_thread_register() " "before calling any pjlib functions." (../src/pj/os_core_unix.c: pj_thread_this: 844)
Fault thread info:
Tid:6719, Name:OS_AudioWriteCB
#00 pc 00000000000fb05d /system/lib/ld-musl-x86_64.so.1(raise+141)(0256d51fc65a13f36584ed47fd3152bb)
#01 pc 00000000000a2831 /system/lib/ld-musl-x86_64.so.1(abort+17)(0256d51fc65a13f36584ed47fd3152bb)
#02 pc 00000000000a2aec /system/lib/ld-musl-x86_64.so.1(__assert_fail+508)(0256d51fc65a13f36584ed47fd3152bb)
#03 pc 000000000028b4c1 /data/storage/el1/bundle/libs/x86_64/libho_pjsip.so(pj_thread_this+65)(a131d36c44e5c5c1372741c77caa2004d10c4fc4)
Registers:
rax:0000000000000000 rdx:0000000000000000 rcx:00007ff3e01fc05d rbx:0000000000000000
rsi:00007ff3be2b8028 rdi:0000000000000002 rbp:00007ff3be2b80c0 rsp:00007ff3be2b8020
r8:00000000000000d8 r9:00007ff3e0242288 r10:0000000000000008 r11:0000000000000246
r12:00007ff3c19454e2 r13:00007ff3be2b8150 r14:0000000000000006 r15:000000000000034c rip:00007ff3e01fc05d
Other thread info:
并根据提示修改修改如下,上述的报错依然存在,请问有什么建议吗
static int32_t AudioRendererOnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t bufferLen) {
pj_thread_desc desc;
pj_thread_t *pthread = NULL;
if (!pj_thread_is_registered()) {
pj_thread_register("media", desc, &pthread);}
}
错误的意思是你在初始化pjsip之前就调用的pjlib的方法,应该是你的调用流程存在问题,检查一下你的Endpoint是否正确初始化,错误中所说的pj_thread_register 方法会在 EndPoint::libCreate 方法调用,并对pjsip进行初始化,大概调用过程是 EndPoint::libCreate => pjsua_create => pj_init => pj_thread_init => pj_thread_register
然后在 pj_thread_register 中使用 rc = pj_thread_local_set(thread_tls_id, thread); 进行线程申请,源码位置 pjproject/pjlib/src/pj/os_core_unix.c 第593行,所以检查一下你 EndPoint::libCreate 是否正确调用
另外PJSIP官网有一个例子,就是初始化Endpoint,并发起注册,你可以参考一下https://docs.pjsip.org/en/latest/pjsua2/hello_world.html#c
Endpoint ep 这样方式创建Endpoint并不能长期持有,应该就是这里有问题,这个ep会在方法执行完后自动释放,使用new创建试试
另外 pj_thread_register 这个方法应该交给pjsip自己内部去调用,目前我还没遇到需要自己去调用pj_thread_register方法的场景,不过我也不一定对,如果你对这个方法的作用非常清楚的话,那当我没说
非常感谢您的回复:
根据建议查了一下,EndPoint::libCreate是正确调用的,并测试自己创建一个线程并在线程调用pj_thread_register正常;但调用ohaudio模块还是会提示上面的错误,请问还有什么建议帮助排查?
代码如下:
try{
Endpoint ep
ep.libCreate();
// Init library
LogWriter* logger = new MyLogWriter();
EpConfig ep_cfg ;
ep_cfg.logConfig.consoleLevel = 4;
ep_cfg.logConfig.writer = logger;
ep_cfg.logConfig.level = 5;
ep.libInit(ep_cfg );
// Transport
TransportConfig tcfg;
tcfg.port = 5060;
ep.transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
// Start library
ep.libStart();
} catch (Error & err) {
}
创建现场及注册
std::thread t(callFunction);
void callFunction() {
try{
pj_thread_desc desc;
pj_thread_t *pthread = NULL;
if (!pj_thread_is_registered()) {
int status = pj_thread_register("makeCall", desc, &pthread);
if (status == SUCCESS) {
OH_LOG_Print(LOG_APP, LOG_FATAL, 0, "Pjsua", "PJSUA2 pj_thread_register");
}
}} catch (pj::Error &e) {}
}
返回信息
您好,非常感谢您的回复,我这边使用oh模拟器调用pjsip也是参考pjsp-apps里面的samples,目前可以正常注册,并按照pjsua2-demo.cpp可以建立语音通话,只不过音频流使用的沙箱音频文件,代码如下,
void MyCall::onCallMediaState(OnCallMediaStateParam &prm)
{
PJ_UNUSED_ARG(prm);
CallInfo ci = getInfo();
AudioMedia aud_med;
AudioMedia& play_dev_med =
MyEndpoint::instance().audDevManager().getPlaybackDevMedia();
if (ci.state == PJSIP_INV_STATE_CONFIRMED ||ci.state == PJSIP_INV_STATE_CONNECTING) {
try {
// Get the first audio media
aud_med = getAudioMedia(-1);
if (!wav_player) {
wav_player = new AudioMediaPlayer();
try {
wav_player->createPlayer(
"/data/storage/el2/base/haps/entry/files/input.wav", 0);
} catch (...) {
std::cout << "Failed opening wav file" << std::endl;
delete wav_player;
wav_player = NULL;
}
}
This will connect the wav file to the call audio media
if (wav_player)
wav_player->startTransmit(aud_med);
// And this will connect the call audio media to the sound device/speaker
aud_med.startTransmit(play_dev_med);
} catch(...) {
std::cout << "Failed to get audio media" << std::endl;
return;}
}
}
随后,改为使用mic录音作为音频流出现提示需要调用pj_thread_register,从日志看在调用ohaudio 开始录音/播放API会创建线程再进行数据回调,因此,在OH_AudioRenderer_OnWriteData这类回调函数调用pj_thread_register;并测试若在线程使用pjsip内部方法需要pj_thread_register,您那边是在线程里调用pjsip方法也不用去调用pj_thread_register方法吗?
OH_AudioRenderer_Start(audioRenderer);
OH_AudioCapturer_Start(audioCapturer);
[SetCaptureMode]Set mode to CAPTURE_MODE_CALLBACK
[ReadCallbackFunc]Thread start, sessionID :100101
[InitCallbackBuffer]InitCallbackBuffer with duration 20000,
方便问一下,您那边是否按照ohaudio以进行适配pjsip,可以实现在oh内使用mic录音及播放的sip语音通话吗?
你把流存文件是要有录音需求么?我没有存文件,ohaudio的能力可以支持pjsip,我的大概实现流程是如下
1.pjsip 设置空设备,因为pjsip内置的音频设备控制无法直接控制ohaudio
2.pjsip实现一个媒体端口MediaPort的onFrameRequested和onFrameReceived
3.创建出入队列,队列作为pjsip和ohaudio的中间缓冲,因为两侧buffer长度不同,速率也不同,所以需要缓冲
4.ohaudio实现AudioRendererOnWriteData和AudioCapturerOnReadData用来对接两个队列
所以音频的流转过程大概是这样:
我这边没有涉及到需要创建线程pj线程的场景,所以没用到 pj_thread_register
我也遇到了一些问题,就是连续拨打几通电话之后,使用 OH_AudioRenderer_Release(audioRenderer)释放音频设备会出现释放不掉的情况,没有任何异常日志输入,然后系统会卡住,不能再进行注册或者呼叫,如果你有类似问题的解决思路,还请指点一下
您好,目前这边还没进展到您的那么快,这边适配ohaudio的思路,大概流程如下:
1、这边查看ohaudio 使用的opensles,所以就参考pjmedia模块里面pjmedia-audiodev->opensl_dev.c进行适配,参考https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/replace-opensles-by-ohaudio-V5 opensl 切换ohaudio
2、pjlib模块里面pj 创建config_site.h #define PJMEDIA_AUDIO_DEV_HAS_OPENSL 1,编译库文件再使用
3、目前通过这个方式也可以打通,pjsip与ohaudio中间转换有问题
抱歉,我对opensl不了解,帮不了你
您好,pjsip与ohaudio中间转换,转换有点问题,能帮忙看一下给点思路吗,非常感谢!
//samplingRate 16000 , 16, 1
static int32_t AudioRendererOnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t bufferLen) {
try{
int status;
if (mStream->play_thread_initialized == 0 || !pj_thread_is_registered())
{
pj_bzero(mStream->play_thread_desc, sizeof(pj_thread_desc));
status = pj_thread_register("opensl_play", mStream->play_thread_desc,
&mStream->play_thread);
mStream->play_thread_initialized = 1;
PJ_LOG(4, (THIS_FILE, "opensl Player thread started"));
}
if (!mStream->quit_flag) {
pjmedia_frame frame;
// char * buf;
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
frame.buf = buffer;//buf = mStream->playerBuffer[mStream->playerBufIdx++];
frame.size = mStream->playerBufferSize;//playerBufferSize :640
frame.timestamp.u64 = mStream->play_timestamp.u64;
frame.bit_info = 0;
status = (*mStream->play_cb)(mStream->user_data, &frame);//play_cb pjmedia_aud_play_cb
if (status != PJ_SUCCESS || frame.type != PJMEDIA_FRAME_TYPE_AUDIO){
pj_bzero(buffer, mStream->playerBufferSize);//mStream->playerBufferSize
}
mStream->play_timestamp.u64 += mStream->param.samples_per_frame /
mStream->param.channel_count;
// pj_memcpy(buffer,buf, mStream->playerBufferSize);
// mStream->playerBufIdx %= NUM_BUFFERS;
}
}catch(...){
PJ_LOG(4, (THIS_FILE, "opensl AudioRendererOnWriteData Error "));
}
return 0;
}
static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t bufferLen) {
try{
int status;
if (mStream->rec_thread_initialized == 0 || !pj_thread_is_registered())
{
// pj_bzero(mStream->rec_thread_desc, sizeof(pj_thread_desc));
status = pj_thread_register("opensl_rec", mStream->rec_thread_desc,
&mStream->rec_thread);
PJ_UNUSED_ARG(status); /* Unused for now.. */
mStream->rec_thread_initialized = 1;
}
if (!mStream->quit_flag) {
pjmedia_frame frame;
char *buf;
// mStream->recordBufferSize = bufferLen;
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
frame.buf = buffer;//buf = mStream->recordBuffer[mStream->recordBufIdx++];
frame.size = mStream->recordBufferSize;
frame.timestamp.u64 = mStream->rec_timestamp.u64;
frame.bit_info = 0;
status = (*mStream->rec_cb)(mStream->user_data, &frame);
mStream->rec_timestamp.u64 += mStream->param.samples_per_frame /
mStream->param.channel_count;
/* And now enqueue next buffer */
// result = (*bq)->Enqueue(bq, buf, stream->recordBufferSize);
// if (result != SL_RESULT_SUCCESS) {
// PJ_LOG(3, (THIS_FILE, "Unable to enqueue next record buffer !!! %d",
// result));
// }
// pj_memcpy(buf,buffer, mStream->recordBufferSize);
mStream->recordBufIdx %= NUM_BUFFERS;
}
}catch(...){
PJ_LOG(4, (THIS_FILE, "opensl Recorder Error "));
}
return 0;
}
您好,我这边opensl的适配也是参考pjsip里面的opensl_dev.c代码,您上面适配思路,有参考的文档吗,对pjsip实现一个媒体端口MediaPort不了解,想根据您的思路试试
https://github.com/pjsip/pjproject/blob/master/pjsip-apps/src/samples/pjsua2_demo.cpp
你可以看看这个官方的例子,第53行就是实现的媒体端口,思路就是我之前说的使用队列做中间缓冲队列连接ohaudio和pjsip的媒体端扣
您好,当前pjproject版本是2.13.1, pjsua2_demo.cpp使用的AudioMediaPort,是需要把pjproject-2.13.1工程里的pjsip模块单独更新,还是整个pjproject都需要更新?
我用的 pjproject-2.14.1
您好,您那边是否也对oh视频通话进行适配了,有什么思路还请指点一下,非常感谢!
暂时没有计划,可能后面会做吧
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
登录 后才可以发表评论