产品简介

QttAudio是由成都擎天树科技有限公司研发的一套跨平台的音频开发框架,支持Android、iOS、Windows、Linux及嵌入式Linux系统,集成了声学回声消除、噪音抑制、自动增益、多路混音等音频处理单元,内置Opus、Speex、PCM等编解码器,自带RTP传输协议模块,提供统一的音频采集与播放接口,让开发者告别复杂的音频处理技术,恼人的回声噪音等现象,专注于音频应用逻辑实现。

产品优势

1. 高清语音质量

声学回声消除(AEC)、噪音抑制(NS)、自动增益(AGC)

2. 多种编码格式

内置Opus、Speex以及PCM编解码

3. 多平台支持

支持Android、iOS、Windows、Linux及嵌入式Linux系统,跨平台一致性和简单性,使用QttAudio提供的音频采集和播放接口,至多10行代码,3分钟让开发者无需再关心回声消除

4. 支持多声音混音

实时接收多路音频输入,输出混音音频

5. 支持RTP协议

只需一行代码,实现RTP协议的语音传输;开发者也可直接通过采集&播放接口,实现私有协议传输,更安全适用

6. 不捆绑云服务

时下几家提供的语音通信云服务,他们通过高度的封装,将后台通信控制与客户端捆绑而成的SDK,开发者只能在他们划定的框架下行事,更长远来说,成本和技术核心却很不可控。 QttAudio SDK更加的可定制化、自由化以及成本优势,应用领域也不仅限于移动应用间的VOIP通话,还可适用于现场扩音,楼宇对讲,嵌入式Linux设备,桌面设备等均可使用。

快速入门

 1.  示例

下面的小例子演示将采集的音频回放功能。如果是普通代码实现声音的采集回放,没有回声处理,则放出来声音会被采集到形成回声,不断激励进而产生啸叫。
使用QttAudio API进行音频采集与播放,相比系统接口更加简洁清晰,而且音质清晰,没有回声。

1.1 Java(Android)
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        try {
            //初始化QttAudioEngine
            QttAudioEngine.me().init(this, "your appkey");
            //创建QttAudioStream
            QttAudioStream stream = QttAudioEngine.me().createStream();
            //设置mic的编码参数,pcm,单声道,48000hz采样率
            QttAudioEngine.me().setMicCodecParams("pcm", 1, 48000, 0);
            //设置mic采集回调函数
            QttAudioEngine.me().setMicCaptureCb(new QttCaptureCallbak() {
                @Override
                public void onCapture(byte[] buf, int bufLength, Object userdata) {
                    QttAudioStream tmpStream = (QttAudioStream) userdata;
                    //将mic采集到的播放出来,实现音频回放功能
                    tmpStream.playBuffer(buf, 0, bufLength);
                }
            }, stream);
            //启动stream,开始工作
            stream.start();
        } catch (QttException e) {
            e.printStackTrace();
        }
    }
}
1.2  C (iOS、Windows、Linux)
static void onCapture(char *buf, size_t len, void *userdata) {
    QttAudioStream *stream = (QttAudioStream *)userdata;
    //将mic采集到的播放出来,实现音频回放功能
    qtt_stream_write_payload(stream, buf, len);
}

int main() {
    //创建QttAudioEngine
    QttAudioEngine *engine = qtt_engine_init("your appkey");
    if (engine == NULL) {
        fprintf(stderr, "qtt_engine_init fail\n");
        return -1;
    }
    //创建QttAudioStream
    QttAudioStream *stream = qtt_engine_create_stream(engine);
    if (stream == NULL) {
        fprintf(stderr, "qtt_engine_create_stream fail\n");
        return -1;
    }
    //设置mic的编码参数,pcm,单声道,48000hz采样率
    qtt_engine_set_mic_codec_params(engine, "pcm", 1, 48000, 0);
    //设置mic采集回调函数
    qtt_engine_set_mic_capture_callback(engine, onCapture, stream);
    //启动stream,开始工作
    qtt_stream_start(stream);
    char c = getchar();
    qtt_stream_stop(stream);
    qtt_stream_free(stream);
    qtt_engine_free(engine);
    return 0;
}

 2.  功能架构

QttAudio由两部分组成:

QttAudioEngine:负责QttAudio SDK初始化及退出 

QttAudioStream:负责语音流采集播放编解码工作。

 3.  开发教程

 3.1  登录注册 

a.点击右上角注册(无账号)进行注册

          

b.直接点击右上角登陆(有账号)

 3.2  创建应用

a.点击右上角控制台,进入控制台

b. 创建应用,勾选应用平台,填写应用相关信息       c.下载文档&SDK

 3.3  开启SDK开发之旅

创建工程接入SDK,详见开发者文档-SDK&API部分对应开发平台

基础知识

1.  回声消除

很多开发者有一定的误解,认为回声消除只是一个接口,给这个接口传入mic采集的音频数据,传入网络远端的参照数据,就可以得到回声消除后的音频数据,但在android、ios、windows和linux等非实时系统上是行不通的。要达到回声消除功效,实现高清音质,是需要一套系统作业来保证的,这也是QttAudio SDK诞生的原因之一。开发者只需要摒弃旧有的观念,将原来使用系统API进行声音采集和播放的方式,全使用QttAudio SDK提供的API进行操作,开发者则不必再担心回音消除这个问题

2.  噪声抑制

QttAudio提供噪音抑制接口,调节噪音抑制阈值,通话时可过滤掉阈值以下的背景噪音等元素。

3.  静音监测

QttAudio提供静音检测接口,可开启对mic输入端是否有说话声的检测通知功能。

4.  多路混音

通过创建多个QttAudioStream对象,对应每一路语音输入输出,达到自动混音功能。为了屏蔽回音消除与混音流向的复杂性,QttAudio SDK客户端混音功能对于开发者是透明的,且QttAudioEngine对象带一个混音器。当有多个QttAudioStream对象时,QttAudioEngine会将各QttAudioStream对象的输入自动进行混音操作,并将混音的结果返回给各QttAudioStream对象的输出回调里。混音的需求是普遍的,比如最常见的多人语音会议功能,一般来说实现多人语音会议功能有三种模式:

4.1  服务端混音

网络模型:

说明:请咨询客服购买QttAudio Server SDK,支持任意数量会议室混音功能。

优点:服务端网络流量小,与会议在麦人数无关,对客户端流量、网络、性能要求低,稳定性高

缺点:会消耗一点服务端CPU资源

4.2 每个客户端混音

网络模型:

说明:会议在麦的客户端,均将自己mic采集到的说话声发向服务端,服务端将其转发给其余人。

优点:模型简单,实现容易,不需要理解QttAudioStream的混音流向,服务端不需要混音消耗CPU资源,对于配置较差的服务器也可承受。

缺点:服务端网络流量大,客户端下行流量大,与会议在麦人数成正比,多一个在麦人数,服务端网络流量就多一份;且如果某一个客户端想播放自己本地音乐,则也只能讲这段音乐当做一个人说话来处理 ,服务端流量增加。

4.3 会议建立者混音

网络模型:

说明:该模式其实是由服务器混音变成了客户端混音,但又不是每个客户端进行混音,而只由会议建立者进行混音。

优点:流量介于1和2之间,对服务端性能与2一样。

缺点:对会议建立者网络带宽,网络稳定性,终端性能有一定要求,如会议建立者网络带宽或者稳定性不够,则会影响整个会议的通话效果。

4.4 总结

以上三种模式,没有最好的,只有最合适的,请开发者根据自身项目应用场景进行合理规划,几种模式可以搭配使用。从长期带宽成本上考虑,我们推荐第一种方案,如需实现服务端混音功能,请咨询客服购买QttAudio Server SDK,支持任意数量会议室(混音器)。

SDK&API

1.  Android端SDK

如图所示,将sdk拷贝至app/libs目录下

修改app/build.gradle,添加如下信息到图上位置:

sourceSets.main {
    jniLibs.srcDirs = ["libs"]
}
compile files('libs/QttAudioJNI.jar')

修改AndroidManifest.xml,添加权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

 

2.  iOS端SDK

从官网下载SDK,向项目中导入SDK及头文件(QttAudio.h ,libQttAudio.a)

设置系统库依赖:Build Phases->Link Binary With Libraries

添加libQttAudio.a     libz.tdb      libc++.tdb

添加麦克风使用权限:Privacy - Microphone Usage Description

在您需要使用QttAudio SDK 功能的类中,import 相关头文件。

#import "QttAudio.h"

注册(通过官网申请的AppKey进行注册)

QttAudioEngine *engine = qtt_engine_init("AppKey");

创建音频流,设置采集回调并启动

//创建音频流
QttAudioStream *stream = qtt_engine_create_stream(engine);
//设置回调
qtt_stream_set_capture_callback(stream, callback, stream);
//设置编码(可选)
qtt_stream_set_codec_params(stream, "pcm", 1, 16000, 16000);
//启动音频流
qtt_stream_start(stream);

获取实时采集音频数据(相关参数 :buf采集到的音频数据,len音频大小,userData预留,留用户可根据实际情况设置)

void callback(char *buf, size_t len, void *userdata){
    qtt_stream_write_payload(userdata, buf, len);//播放
}

3.  Windows端SDK

以下配置以visual stdio 2013为例:

1.导入引用库QttAudio.h

2.导入引用库QttAudio.lib

3.将QttAudio sdk中提供的所有dll文件复制到工程生成目录

4.  Linux端SDK

5.  嵌入式Linux端SDK

6.  API参考

6.1 java(Android)

QttAudioEngine

/**

* 单例模式,返回QttAudioEngine对象
* @return QttAudioEngine单例对象

*/

public synchronized static QttAudioEngine me() 

/**

* 初始化函数,整个程序期间只调用一次。会有阻塞,建议不要在主线程执行
* @param context
* @param appKey
* @throws QttException 初始化失败则会抛出该异常
*/

public void init(Context context, String appKey) throws QttException

/**

* 释放QTTAudioEngine单例对象,在程序退出时调用该方法。与init方法相对应。
*/

public void free()

/**

* 如果某些机型有回声,在初始化后调用该函数一次并运行一次即可,以后无需再调用
*/

public synchronized void detectEcho()

/**

* 开关扬声器方法
* @param on true: 打开扬声器; false: 关闭扬声器,使用听筒
*/

public void enableSpeaker(boolean on)

/**
* 如果某些特殊机型无法运行,则在init方法调用成功后,调用该函数设置为兼容模式,并传入参数true。
* 该函数一般不需要调用
* @param val true为启用兼容模式;false为不启用兼容模式。
*/

public void enableAudioCompatibilityMode(boolean val)

/**
* 设置mic采集编码的格式
* @param mime "pcm", "opus", "speex"三者之一
* @param channel 1,只支持单声道
* @param samplerate 采样率,8000,16000,32000,44100,48000
* @param bitrate 比特率,当mine设定为"pcm"时,该值无意义,用户传入0即可
*/

public void setMicCodecParams(String mime, int channel,  int samplerate, int bitrate)

/**
* 设置mic采集的增益大小
* @param vol 0至3的范围,当vol为1时是原声大小,为0是完全静音
*/

public void setMicGain(float vol)

/**

* 创建QTTAudioStream音频流
* @return QttAudioStream
*/

public QttAudioStream createStream()

/**
* 是否启用通话降噪功能
* @param on true为启用,false为不启用
*/

public void enableNoiseGate(boolean on)

/**

* 设置通话降噪的阈值,默认为0.05f
* @param val val值越大,降噪越厉害,对于正常说话声音音量要求也更大
*/

public void setNoiseGateThres(float val)

 

QttAudioStream

/**
* 设置QttAudioStream对象的编解码的格式
* @param mime "pcm", "opus", "speex"三者之一
* @param channel 1,只支持单声道
* @param samplerate 采样率,8000,16000,32000,44100,48000
* @param bitrate 比特率,当mine设定为"pcm"时,该值无意义,用户传入0即可
*/

public void setCodecParams(String mime, int channel,  int samplerate, int bitrate)

/**
* 设置RTP网络收发参数,使QttAudioStream对象采用RTP方式传输音频
* @param localRtpPort   本地rtp端口
* @param localRtcpPort  本地rtcp端口
* @param remoteIP       远程目的ip
* @param remoteRtpPort  远程目的rtp端口
* @param remoteRtcpPort 远程目的rtcp端口
* @param mode           1是只接收模式,2是发送&接收模式
* @param idx            设置rtp的载荷类型,通话双方必须要一样
* @param ssrc           设置rtp的ssrc,该字段一般用来区分rtp流
*/

public void setRtpParams(int localRtpPort, int localRtcpPort, String remoteIP, int remoteRtpPort, int remoteRtcpPort, int mode, int ssrc, int idx)

/**
* 设置语音流的mic采集及混音回调函数,通过设置该回调,开发者可以源源不断获得mic采集的混音音频数据
* 该接口与QttAudioEngine的setPayloadCallback不同之处在于,当有多个stream时,该接口获得的是其他stream播
* 放的声音与mic采集的声音的混音后的音频数据,具体数据内容可参见文档x.x节
* @param streamCaptureCB 音频采集回调接口
* @param userdata 用户传进来的对象
*/

public void setCaptureCb(QttCaptureCallbak streamCaptureCB, Object userdata)

/**
* 启动QTTAudioStream对象,开始工作
* @return 0为启动成功,其他为失败
*/

public int start()

/**
* 静音该QTTAudioStream对象
* @param isMute true为静音,false为不静音
*/

public void mute(boolean isMute)

/**
* 设置语音流输出播放音量,影响的是扬声器或听筒的播放音量
* @param vol 正常范围是0-1,1为原音量,可大于1
*/

public void setOutputVolume(float vol)

/**
* 设置语音流输入采集音量
* @param vol 正常范围是0-1,1为原音量,可大于1
*/

public void setInputVolume(float vol)

/**

* 停止语音流,与start方法对应
*/

public void stop()

/**
* 释放语音流,与构造函数或者说QTTAudioEngine.me().createStream()对应
*/

public void free()

/**

* 播放音频buf,听筒或者扬声器就会放出声音来
* @param buffer 音频buffer
* @param offset buffer偏移量,没有偏移量就是0
* @param length buffer长度
*/

public void playBuffer(byte[] buffer, int offset, int length)
6.2 C API(iOS、Windows、Linux)
/**

初始化QttAudioEngine,程序启动时调用

@param appKey 网站注册时申请的appKey

@return 如果为NULL表示初始化失败

*/

QTT_PUBLIC QttAudioEngine *qtt_engine_init(const char *appKey);

/**

释放QttAudioEngine,程序退出时调用

@param engine

*/

QTT_PUBLIC void qtt_engine_free(QttAudioEngine *engine);

/**

设置mic采集回调函数,通过设置该回调,开发者可以源源不断获得mic采集的音频数据。

该接口与qtt_stream_set_capture_callback不同之处在于,该接口只获取mic采集的声音,而stream回调包含了混音部分

@param engine QttAudioEngine指针

@param callback 回调函数

@param userdata

*/

QTT_PUBLIC void qtt_engine_set_mic_capture_callback(QttAudioEngine *engine, QttCaptureCallback callback, void *userdata);

/**

设置mic采集数据的编码格式

@param engine QttAudioEngine指针

@param mime 可以是"opus","speex","pcm"

@param channel 1单声道或者2双声道

@param samplerate 采样率,一般是8000,16000,32000,44100,48000

@param bitrate 比特率,一般是16000,28000,32000,48000,64000,96000等;当mime设置为“pcm"时,比特率设置由channel和samplerate决定了,该参数无效,设置为0即可

*/

QTT_PUBLIC void qtt_engine_set_mic_codec_params(QttAudioEngine *engine, char *mime, int channel, int samplerate, int bitrate);

/**

开启\关闭 噪音抑制

@param engine QttAudioEngine指针

@param val true: 开启; false: 关闭

*/

QTT_PUBLIC void qtt_engine_enable_noise_suppression(QttAudioEngine *engine, bool_t val);

/**

设置噪音抑制的阈值

@param engine QttAudioEngine指针

@param val 默认为0.05f,开发者可根据实际场景对该值进行调节

*/

QTT_PUBLIC void qtt_engine_set_ng_thres(QttAudioEngine *engine, float val);

/**

检测回声时延

对与某些特殊机型有回声的情况,调用该函数测量该机型的回声时延

@param engine QttAudioEngine指针

@return 回声时延,毫秒

*/

QTT_PUBLIC int qtt_engine_detect_echo(QttAudioEngine *engine);

/**

是否需要检测回声时延

@param engine QttAudioEngine指针

@param needDetect true为需要,false为不需要

*/

QTT_PUBLIC void qtt_engine_need_detect_echo(QttAudioEngine *engine, bool_t needDetect);

/**

设置回声时延

@param engine QttAudioEngine指针

@param delay 毫秒

*/

QTT_PUBLIC void qtt_engine_set_delay(QttAudioEngine *engine, int delay);

/**

设置mic的音量

@param engine QttAudioEngine指针

@param gain 增益百分比,1f表示100%,0表示无声,可以大于1f,建议在0-3f之间

*/

QTT_PUBLIC void qtt_engine_set_mic_volume(QttAudioEngine *engine, float gain);

/**

设置静音事件检测回调函数

@param engine QttAudioEngine指针

@param eventNotify 事件回调函数

@param userdata 用户传的任意data

*/

QTT_PUBLIC void qtt_engine_set_silence_detected(QttAudioEngine *engine, OnEventNotifyCallback eventNotify, void *userdata);

/**

设置静音事件检测的阈值

@param engine QttAudioEngine指针

@param val 阈值默认为0.01f,开发者可根据实际场景调节它

*/

QTT_PUBLIC void qtt_engine_set_silence_detected_threshold(QttAudioEngine *engine, float val);

#if defined(_WIN32) || defined(__linux__) && !defined(__ANDROID__)

/**

获得采集和播放的声音设备列表

@param engine QttAudioEngine指针

@param snds 声音设备列表

*/

QTT_PUBLIC void qtt_get_card_list(QttAudioEngine *engine, std::vector<SoundDevice> &snds);

/**

设置声音播放设备

@param engine QttAudioEngine指针

@param id SoundDevice的id

*/

QTT_PUBLIC void qtt_set_play_card_by_id(QttAudioEngine *engine, char *id);

/**

设置声音采集设备

@param engine QttAudioEngine指针

@param id SoundDevice的id

*/

QTT_PUBLIC void qtt_set_capt_card_by_id(QttAudioEngine *engine, char *id);

#endif

/**

创建一个QttAudioMixer混音器

@param engine QttAudioEngine指针

@return 如果为NULL表示创建QttAudioMixer失败

*/

QTT_PUBLIC QttAudioMixer *qtt_engine_create_mixer(QttAudioEngine *engine);

/**

创建一个属于QttAudioMixer混音器的QttAudioStream,用QttAudioMixer创建的QttAudioStream不会涉及声音的采集与播放,只是纯粹用来作为混音使用

@param mixer QttAudioMixer指针

@return 如果为NULL表示创建QTTAudioStream失败

*/

QTT_PUBLIC QttAudioStream *qtt_mixer_create_stream(QttAudioMixer *mixer);

/**

当不使用该mixer时,请及时释放它

在调用该函数前,请保证该mixer创建的所有QTTAudioStream对象都stop或free了

@param mixer QttAudioMixer指针

@return 0,成功;

*/

QTT_PUBLIC int qtt_mixer_free(QttAudioMixer *mixer);

/**

创建QttAudioStream

@param engine QttAudioEngine指针

@return 如果为NULL表示创建QTTAudioStream失败

*/

QTT_PUBLIC QttAudioStream *qtt_engine_create_stream(QttAudioEngine *engine);

/**

通过id获得QttAudioStream

@param engine QttAudioEngine指针

@param id QttAudioStream的id

@return QttAudioStream

*/

QTT_PUBLIC QttAudioStream *qtt_engine_get_stream_by_id(QttAudioEngine *engine, int id);

/**

android用户使用,某些android特殊机型如声音无法正常采集或播放,需要调用该函数,并将val置为true

@param engine QttAudioEngine指针

@param val true: 打开兼容模式; false: 关闭兼容模式

*/

QTT_PUBLIC void qtt_engine_set_compatibility_audio_mode(QttAudioEngine *engine, bool_t val);

/**

设置音频流编解码参数

@param stream     QttAudioStream指针

@param mime       "opus","speex","pcm"

@param channel    1单声道或者2双声道

@param samplerate 采样率,一般是8000,16000,32000,44100,48000

@param bitrate    比特率,一般是16000,28000,32000,48000,64000,96000等;当mime设置为“pcm"时,比特率设置由channel和samplerate决定了,该参数无效,设置为0即可

*/

QTT_PUBLIC void qtt_stream_set_codec_params(QttAudioStream *stream, char *mime, int channel, int samplerate, int bitrate);

/**

对qtt_stream_set_codec_params的包装,内置默认参数

@param stream QttAudioStream指针

@param mime "opus","speex","pcm"

*/

QTT_PUBLIC void qtt_stream_set_codec_default_params(QttAudioStream *stream, char *mime);

/**

针对windows

@param stream QttAudioStream指针

@param out 输出字符串

*/

QTT_PUBLIC void qtt_stream_get_fmtp(QttAudioStream *stream, char *out);

/**

获得QttAudioStream的唯一标识id

@param stream QttAudioStream指针

@return id

*/

QTT_PUBLIC int qtt_stream_get_id(QttAudioStream *stream);

/**

设置RTP网络收发参数

QttAudioStream内置RTP收发模块,如果开发者采用RTP协议进行音频数据传输,则直接调用该接口设置收发参数

@param stream         QttAudioStream指针

@param localRtpPort   本地rtp端口

@param localRtcpPort  本地rtcp端口

@param remoteIP       远程目的ip

@param remoteRtpPort  远程目的rtp端口

@param remoteRtcpPort 远程目的rtcp端口

@param mode           1是只接收模式,2是发送&接收模式

@param ssrc           设置rtp的ssrc,该字段一般用来区分rtp流

@param idx            设置rtp的载荷类型,通话双方必须要一样

*/

QTT_PUBLIC void qtt_stream_set_rtp_params(QttAudioStream *stream, int localRtpPort, int localRtcpPort, char *remoteIP, int remoteRtpPort, int remoteRtcpPort, int mode, int ssrc, int idx);

/**

设置该QTTAudioStream为播放文件的流

@param stream   QttAudioStream指针

@param filename 文件名,播放的文件需是wav格式,后续版本会支持mp3格式

*/

QTT_PUBLIC void qtt_stream_set_file_params(QttAudioStream *stream, const char *filename);

/**

启动QTTAudioStream

@param stream QttAudioStream指针

@return 0为成功,其他为失败

*/

QTT_PUBLIC int qtt_stream_start(QttAudioStream *stream);

/**

是否静音QttAudioStream

@param stream QttAudioStream指针

@param mute   true为静音,false为不静音

*/

QTT_PUBLIC void qtt_stream_mute(QttAudioStream *stream, bool_t mute);

/**

设置播放的音量

@param stream QttAudioStream指针

@param val    增益百分比,1f表示100%,0表示无声,可以大于1f,建议在0-3f之间

*/

QTT_PUBLIC void qtt_stream_set_output_volume(QttAudioStream *stream, float val);

/**

设置输入的音量

@param stream QttAudioStream指针

@param val    增益百分比,1f表示100%,0表示无声,可以大于1f,建议在0-3f之间

*/

QTT_PUBLIC void qtt_stream_set_input_volume(QttAudioStream *stream, float val);

/**

停止QttAudioStream

@param stream QttAudioStream指针

*/

QTT_PUBLIC void qtt_stream_stop(QttAudioStream *stream);

/**

释放QttAudioStream

@param stream QttAudioStream指针

*/

QTT_PUBLIC void qtt_stream_free(QttAudioStream *stream);

/**

设置QttAudioStream的输出回调函数,通过设置该回调,开发者可以源源不断获得该stream输出的音频数据

@param stream   QttAudioStream指针

@param callback 音频回调接口

@param userdata 用户数据

*/

QTT_PUBLIC void qtt_stream_set_capture_callback(QttAudioStream *stream, QttCaptureCallback callback, void *userdata);

/**

向QttAudioStream里写入音频buf

如果该QttAudioStream是QttAudioEngine创建的,则会播放出声音来

@param stream

@param buf    音频buf

@param len    音频buf的长度,大小不建议大于1400

*/

QTT_PUBLIC void qtt_stream_write_payload(QttAudioStream *stream, char *buf, size_t len);

联系我们

1.   联系邮箱

support@qingtiantree.com

2.   技术客服QQ

3293059790