功能使用
1 摄像头参数配置
所有摄像头相关的配置,都在 CameraStreamingSetting 类中进行。
1.1 前置/后置摄像头配置
const mCameraStreamingSetting = new CameraStreamingSetting()
mCameraStreamingSetting().setCameraFacingType(CAMERA_FACING_TYPE.BACK)
mCameraStreamingSetting().setCameraFacingType(CAMERA_FACING_TYPE.FRONT)
注:默认
若设定的摄像头打开失败,将会回调
1.2 Camera 对焦相关
- setFocusModeEnabled
若希望关闭自动对焦功能,可以:
mCameraStreamingSetting().setFocusModeEnabled(false)
注:默认开启
- 通过 setFocusMode 设置对焦模式
mCameraStreamingSetting().setFocusMode(CAMERA_FOCUS_MODE.FOCUS_MODE_CONTINUOUS_AUTO)
注:目前仅支持自动对焦,手动对焦后续版本支持
1.3 Camera 预览 size
为了兼容更多的 Camera ,SDK 采用了相关的措施:
- 使用
PREVIEW_SIZE_LEVEL 和PREVIEW_SIZE_RATIO 共同确定一个 Preview Size
SDK 目前分别支持的
// PREVIEW_SIZE_LEVEL
- SMALL
- MEDIUM
- LARGE
// PREVIEW_SIZE_RATIO
- RATIO_4_3
- RATIO_16_9
1.4 镜像模式
对于有对前置摄像头进行 Mirror 操作的用户来说,只需通过
let isMirror: boolean = false // false as default
mCameraStreamingSetting.setFrontCameraMirror(isMirror)
2 麦克风参数配置
所有麦克风相关的配置,都在 MicrophoneStreamingSetting 类中进行。
2.1 设置采样率
SDK 默认采样率为 48000 Hz,若需要更改音频采集的采样率,可通过调用如下接口实现:
const mMicrophoneStreamingSetting = new MicrophoneStreamingSetting()
mMicrophoneStreamingSetting.setSampleRate(MICROPHONE_SAMPLE_RATE.SAMPLE_RATE_48000)
目前支持的采样率为:
// MICROPHONE_SAMPLE_RATE
- SAMPLE_RATE_8000
- SAMPLE_RATE_11025
- SAMPLE_RATE_12000
- SAMPLE_RATE_16000
- SAMPLE_RATE_22050
- SAMPLE_RATE_24000
- SAMPLE_RATE_32000
- SAMPLE_RATE_44100
- SAMPLE_RATE_48000
- SAMPLE_RATE_64000
- SAMPLE_RATE_88200
- SAMPLE_RATE_96000
- SAMPLE_RATE_176400
- SAMPLE_RATE_192000
3 推流参数设置
所有推流相关的参数配置,都在 StreamingProfile 类中进行。
3.1 推流地址配置
从 v2.0.0 开始,在七牛加入推流域名白名单之后,可以使用如下接口直接推流:
mProfile.setPublishUrl("rtmp://xxx.xxx/xxx/xxx")
其中,推流地址的生成方式可参考服务端文档
3.2 AVProfile
当需要自定义 video 的 fps、bitrate、profile 或者 audio 的 sample rate、bitrate,可以通过 AVProfile 设置。
AVProfile 的使用例子如下:
// audio sample rate is 44100, audio bitrate is 48 * 1024 bps
const aProfile: AudioProfile = new AudioProfile(44100, 48 * 1024);
// fps is 20, video bitrate is 1000 * 1024 bps, maxKeyFrameInterval is 60, profile is HIGH
const vProfile: VideoProfile = new VideoProfile(20, 1000 * 1024, 60, H264Profile.HIGH)
const avProfile: AVProfile = new AVProfile(vProfile, aProfile)
mStreamingProfile.setAVProfile(avProfile)
最终设定的值应该为:
- 音频:48 * 1024, 44100
- 视频:20, 1000 * 1024, 60
3.3 码率控制模式
可通过设置 EncoderRCModes 指定推流的码率控制模式,目前 RC mode 支持的类型:
- EncoderRCModes.VBR: 质量优先,实际的码率可能高于设置的码率
- EncoderRCModes.CBR: 码率优先,更精确地码率控制
可通过 StreamingProfile 的 setEncoderRCMode 方法进行设置,如下:
mStreamingProfile.setEncoderRCMode(EncoderRCModes.CBR)
注:默认值为 EncoderRCModes.VBR
3.4 Encoding size 的设定
SDK 将 Preview size 和 Encoding size 已经分离,他们之间互不影响。Preview size 代表的是 Camera 本地预览的 size,encoding size 代表的是编码时候的 size,即播放端不做处理时候看到视频的 size。
设置方法如下:
mStreamingProfile.setPreferredVideoEncodingSize(int, int)
3.5 StreamStatus 反馈配置
对于推流信息的反馈,可以通过
mStreamingProfile.setStreamStatusConfig(new StreamStatusConfig(3)); // 单位为秒
其含义为,若注册了
3.6 自适应码率
由于无线网络相对于有线网络,可靠性较低,会经常遇到信号覆盖不佳导致的高丢包、高延时等问题,特别是在用网高峰期,由于带宽有限,网络拥塞的情况时有发生。可以通过如下 API 开启自适应码率(注意:SDK 默认是关闭自适应码率的):
/**
* adaptive bitrate adjust mode
*/
enum BitrateAdjustMode {
Auto, // SDK 自适应码率调节
Manual, // 用户自己实现码率调节, 范围:10kbps~10Mbps
Disable // 关闭码率调节
}
mProfile.setBitrateAdjustMode(BitrateAdjustMode.Auto);
开启自适应码率后,当 SDK 检测到网络状况差时,会尝试降低码率,直到 150 Kbps;反之,会提升码率,直到用户设定的 Target Bitrate(通过 StreamingProfile#VideoProfile 设定的码率值)
另外,可以通过下面接口控制自适应码率调节的范围:
/**
* Sets the range value of video adaptive bitrate.
*
* @param minBitrate min bitrate, unit: bps
* @param maxBitrate max bitrate, unit: bps
* */
mProfile.setVideoAdaptiveBitrateRange(minBitrate, maxBitrate)
此时,码率调节策略为:
- 用户网络没有触发自动码率调节,码率一直保持在 Target Bitrate(通过 StreamingProfile#VideoProfile 设定的码率值)附近
- 触发自动码率调节后:
- 向下:
- 逐级调整,直到自适应码率调节范围的下限(minBitrate)
- 向上:
- 如果调节范围的上限 (maxBitrate) 大于 Target Bitrate,最高会调整到 Target Bitrate
- 如果调节范围的上限 (maxBitrate) 小于 Target Bitrate,最高会调整到调节范围的上限(maxBitrate)
- 向下:
3.7 视频编码格式设置
支持设置 H.264 或 H.265 编码格式,默认使用 H.264 编码格式。
enum VideoEncodeType {
H264,
HEVC
}
mProfile,setVideoEncodeType(VideoEncodeType.HEVC);
4 核心类 MediaStreamingManager
所有音视频推流相关的具体操作,都在 MediaStreamingManager 中进行。
4.1 构造 MediaStreamingManager
在构造 MediaStreamingManager 阶段会确定其编码的类型,目前 SDK 支持的编码类型有:
enum AVCodecType {
HW_AUDIO_CODEC, // 纯音频硬编
HW_VIDEO_SURFACE_CODEC, // 纯视频硬编
HW_VIDEO_SURFACE_CODEC_WITH_HW_AUDIO_CODEC, //音视频硬编
}
const mContext = getContext(this);
mMediaStreamingManager = new MediaStreamingManager(mContext, AVCodecType.HW_VIDEO_SURFACE_CODEC_WITH_HW_AUDIO_CODEC);
构造完毕后,需调用
mMediaStreamingManager.prepare(profile, microphoneStreamingSetting, xComponent, cameraStreamingSetting);
其中
4.2 设置 Listener
为了更好的和 SDK 交互,接受各种状态和其他信息,需要注册对应的 Listener:
mMediaStreamingManager.on("stateChanged", (state: StreamingState) => {
})
mMediaStreamingManager.on('streamStatusChanged', (status: StreamStatus) => {
})
onStateChanged 中 status 的类型分别为:
enum StreamingState {
UNKNOWN,
PREPARING,
READY,
CONNECTING,
STREAMING,
SHUTDOWN,
IOERROR,
SENDING_BUFFER_EMPTY,
SENDING_BUFFER_FULL,
SENDING_BUFFER_HAS_FEW_ITEMS,
SENDING_BUFFER_HAS_MANY_ITEMS,
DISCONNECTED,
NO_SUPPORTED_PREVIEW_SIZE,
AUDIO_RECORDING_FAIL,
START_VIDEO_ENCODER_FAIL,
START_AUDIO_ENCODER_FAIL,
INVALID_STREAMING_URL,
UNAUTHORIZED_STREAMING_URL
}
StreamStatus 的定义如下:
/**
* The nested class is for feedbacking the av status in real time.
*
* <p>
* You can set the {@link StreamStatusConfig} to get the preferred callback frequency.
*
* */
class StreamStatus {
/**
* Audio frame per second.
* */
public audioFps: number;
/**
* Video frame per second.
* */
public videoFps: number;
/**
* Audio and video total bits per second.
* */
public totalAVBitrate: number; // bps
/**
* Audio bits per second.
* */
public audioBitrate: number; // bps
/**
* Video bits per second.
* */
public videoBitrate: number; // bps
/**
* Number of dropped video frames in callback period.
* */
public droppedVideoFrames: number;
}
4.3 开始推流
开始进行推流:
mMediaStreamingManager.startStreaming();
4.4 闪光灯操作
开启闪光灯:
mMediaStreamingManager.turnLightOn();
关闭闪光灯:
mMediaStreamingManager.turnLightOff();
4.5 切换摄像头
切换摄像头。
mMediaStreamingManager.switchCamera();
4.6 禁音推流
在推流过程中,将声音禁用掉:
mMediaStreamingManager.mute(true);
恢复声音:
mMediaStreamingManager.mute(false);
4.7 发送 sei
this.streamingManager?.sendSEIMessage(sei, 10) // 10 为循环次数
4.8 图片推流
profile.setPictureStreamingResourceId(rfd)
streamingManager?.togglePictureStreaming()
注:默认为 false
4.7 停止推流
停止当前推流。
mMediaStreamingManager.stopStreaming();
4.8 release
释放不紧要资源。
mMediaStreamingManager.release();
5 水印设置
所有水印相关的配置,都在 WatermarkSetting 类中进行。
5.1 构造 WatermarkSetting
传入 RawFileDescriptor 作为水印资源:
const watermarkSetting = new WatermarkSetting(watermarkRfd, [watermarkX, watermarkY], [watermarkWidth, watermarkHeight], 100); // 100 为 alpha 值
this.streamingManager?.prepare(this.profile, this.microphoneStreamingSetting, this.xComponentContext!, this.cameraStreamingSetting, watermarkSetting)
5.2 动态修改水印配置:
watermarkSetting?.setCustomPosition(x, y)
.setCustomSize(width, height)
.setAlpha(90)
.setResourceId(rfd)
this.streamingManager?.updateWatermarkSetting(watermarkSetting)
6 屏幕录制
6.1 构造核心类 ScreenStreamingManager
const streamingManager = new ScreenStreamingManager(context, AVCodecType.HW_VIDEO_SURFACE_CODEC_WITH_HW_AUDIO_CODEC)
streamingManager?.prepare(profile, microphoneStreamingSetting)
streamingManager?.startStreaming()
streamingManager?.stopStreaming()
6.2 常驻后台
再使用屏幕录制时,需要使用以下代码常驻后台:
let wantAgentInfo: wantAgent.WantAgentInfo = {
wants: [
{
bundleName: "com.qiniu.pili.harmony.streaming",
abilityName: "com.qiniu.pili.harmony.streaming.EntryAbility"
}
],
operationType: wantAgent.OperationType.START_ABILITY,
requestCode: 0,
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
backgroundTaskManager.startBackgroundRunning(this.context,
backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
streamingManager?.startStreaming();
})
});
关闭常驻后台
await backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
streamingManager?.stopStreaming()
})
7 混音
7.1 初始化混音
const audioMixer = streamingManager?.getAudioMixer()
await audioMixer?.setFile(filePath, true) // true 表示是否循环, filePath 为 resource file
audioMixer.play()
7.2 监听混音状态
this.audioMixer.on("finish", () => {
})