prefacio
En el anterior "Múltiples videollamadas basadas en el SDK de Acoustics Flutter" , nos dimos cuenta perfectamente del efecto de las videollamadas multiplataforma y multipersona a través de Flutter + Acoustics SDK , por lo que en este artículo avanzaremos en base a los ejemplos anteriores. Presente algunas funciones de efectos especiales de uso común, incluido el fondo virtual, la mejora del color, el audio espacial y las funciones básicas de cambio de sonido.
Este artículo lo lleva principalmente a comprender varias implementaciones prácticas de API en el SDK, que son relativamente simples.
01 Fondo virtual
enableVirtualBackground
El fondo virtual es uno de los efectos especiales más comunes en las videoconferencias, y la compatibilidad con el fondo virtual se puede habilitar a través de métodos en Agora SDK . ( Haga clic aquí para ver la documentación de la interfaz de fondo virtual ).
En primer lugar, debido a que lo estamos usando en Flutter, podemos poner una imagen en Flutter assets/bg.jpg
como fondo, aquí hay dos puntos a tener en cuenta:
assets/bg.jpg
La imagen necesita agregar una referenciapubspec.yaml
debajo del archivo.assets
assets:
- assets/bg.jpg
- Necesita
pubspec.yaml
agregarpath_provider: ^2.0.8
ypath: ^1.8.2
depender del archivo, porque necesitamos guardar la imagen en la ruta local de la aplicación
rootBundle
Como se muestra en el siguiente código, primero lo leemos en Flutter bg.jpg
, luego lo convertimos a bytes
, y luego llamamos para getApplicationDocumentsDirectory
obtener la ruta, la guardamos en el directorio de la aplicación /data"
y luego configuramos la ruta de la imagen al enableVirtualBackground
método source
para cargar el virtual. fondo.
Future<void> _enableVirtualBackground() async {
ByteData data = await rootBundle.load("assets/bg.jpg");
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
Directory appDocDir = await getApplicationDocumentsDirectory();
String p = path.join(appDocDir.path, 'bg.jpg');
final file = File(p);
if (!(await file.exists())) {
await file.create();
await file.writeAsBytes(bytes);
}
await _engine.enableVirtualBackground(
enabled: true,
backgroundSource: VirtualBackgroundSource(
backgroundSourceType: BackgroundSourceType.backgroundImg,
source: p),
segproperty:
const SegmentationProperty(modelType: SegModelType.segModelAi));
setState(() {});
}
Como se muestra en la figura a continuación, es el efecto de la operación después de que se enciende la imagen de fondo virtual. Por supuesto, hay dos parámetros que necesitan atención:
BackgroundSourceType
: Puede configurarbackgroundColor
(color de fondo virtual),backgroundImg
(imagen de fondo virtual),backgroundBlur
(desenfoque de fondo virtual), estas tres situaciones pueden cubrir básicamente todas las escenas de la videoconferenciaSegModelType
: Se puede configurar como un algoritmo de matización en dos escenarios diferentessegModelAi
(algoritmo inteligente) o (algoritmo de pantalla verde).segModelGreen
Lo que debe tenerse en cuenta aquí es que en el indicador oficial, se recomienda usar esta función solo en dispositivos equipados con los siguientes chips (deben ser necesarios para la GPU):
- Snapdragon 700 serie 750G y superior
- Snapdragon 800 serie 835 y superior
- Dimensión 700 serie 720 y superior
- Kirin 800 serie 810 y superior
- Kirin 900 serie 980 y superior
Además, cabe señalar que para adaptar la resolución de la imagen de fondo personalizada a la resolución de captura de vídeo del SDK, SoundNet SDK escalará y recortará la imagen de fondo personalizada sin deformarla.
02 belleza
El embellecimiento es otra de las funciones más utilizadas en las videoconferencias, y Shengwang también proporciona setBeautyEffectOptions
métodos para admitir algunos ajustes básicos del efecto de embellecimiento. ( Haga clic para ver el documento de la interfaz de belleza ).
Como se muestra en el código a continuación, setBeautyEffectOptions
el método es principalmente para BeautyOptions
ajustar el estilo de belleza de la pantalla a través del método, y las funciones específicas de los parámetros se muestran en la tabla a continuación.
El .5 aquí es solo un efecto de demostración. Específicamente, puede configurar varias plantillas fijas para que los usuarios elijan de acuerdo con los requisitos de su producto.
_engine.setBeautyEffectOptions(
enabled: true,
options: const BeautyOptions(
lighteningContrastLevel:
LighteningContrastLevel.lighteningContrastHigh,
lighteningLevel: .5,
smoothnessLevel: .5,
rednessLevel: .5,
sharpnessLevel: .5,
),
);
El efecto después de correr se muestra en la siguiente figura. Después de activar el parámetro 0.5, la imagen general del embellecimiento es más justa y el color de los labios también es más obvio.
sin belleza | belleza abierta |
---|---|
![]() |
![]() |
03 Mejora del color
La siguiente API que se presentará es la mejora del color: setColorEnhanceOptions
si la belleza no es suficiente para satisfacer sus necesidades, la API de mejora del color puede proporcionar más parámetros para ajustar el estilo de imagen que necesita. ( Haga clic para ver el documento de la interfaz de mejora del color )
Como se muestra en el siguiente código, la API de mejora del color es muy simple, principalmente ajusta los parámetros ColorEnhanceOptions
l strengthLeve
y skinProtectLevel
, es decir, ajusta el efecto de la intensidad del color y la protección del color de la piel.
_engine.setColorEnhanceOptions(
enabled: true,
options: const ColorEnhanceOptions(
strengthLevel: 6.0, skinProtectLevel: 0.7));
Como se muestra en la figura a continuación, debido a que las imágenes de video capturadas por la cámara pueden tener distorsión de color, y la función de mejora de color puede ajustar de manera inteligente las características del video, como la saturación y el contraste, para mejorar la riqueza y reproducción del color del video, y finalmente hacer que la imagen de video más vivo
Después de activar la mejora, la imagen es más llamativa.
sin mejora | Activa Belleza + Realce |
---|---|
![]() |
![]() |
04 Efectos de sonido espaciales
De hecho, el ajuste de sonido es lo más destacado. Dado que SoundNet se llama SoundNet, no debe quedarse atrás en el procesamiento de audio. En SoundNet SDK, puede abrir el enableSpatialAudio
efecto de los efectos de sonido espacial. ( Haga clic para ver la documentación de la interfaz de audio espacial )
_engine.enableSpatialAudio(true);
¿Qué es el sonido espacial? En pocas palabras, es un efecto de sonido 3D especial , que puede virtualizar la fuente de sonido que se emitirá desde una posición específica en un espacio tridimensional, incluido el plano horizontal del oyente, adelante, atrás, izquierda y derecha, y verticalmente arriba o abajo. .
En esencia, los efectos de sonido espacial se calculan mediante algunos algoritmos relacionados con la acústica para simular la realización de efectos de sonido similares a los efectos 3D espaciales.
Al mismo tiempo, también puede configurar los parámetros relevantes del efecto de sonido espacial, como se muestra en la tabla a continuación, puede ver que la red de sonido proporciona un conjunto muy rico de parámetros que nos permiten ajustar el efecto de sonido espacial de forma independiente, por ejemplo, el setRemoteUserSpatialAudioParams
efecto de suma aquí es muy interesante y muy recomendable. Todos vayan y prueben.enable_blur
enable_air_absorb
Los efectos de audio no se pueden mostrar aquí, y le recomiendo que lo pruebe usted mismo.
05 efectos vocales
Otra API recomendada es el efecto de voz humana: setAudioEffectPreset
llame a este método para modificar la voz del usuario sin cambiar las características de género de la voz original a través del efecto de voz humana preestablecido del SDK (haga clic para ver el documento de la interfaz del efecto de voz humana
_engine.setAudioEffectPreset(AudioEffectPreset.roomAcousticsKtv);
Hay muchos ajustes preestablecidos en SoundNet SDK AudioEffectPreset
, como se muestra en la tabla a continuación, desde efectos de escena como KTV, estudio de grabación, cambio de voz masculina y femenina, hasta efectos de sonido falsos como Zhu Bajie, que se puede decir que es bastante sorprendente.
PD: para obtener mejores efectos vocales, debe configurar setAudioProfile scenario
en :
_engine.setAudioProfile(
profile: AudioProfileType.audioProfileDefault,
scenario: AudioScenarioType.audioScenarioGameStreaming);
Por supuesto, lo que debe tenerse en cuenta aquí es que este método solo se recomienda para procesar voces humanas y no se recomienda para procesar datos de audio que contengan música.
Finalmente, el código completo se ve así:
class VideoChatPage extends StatefulWidget {
const VideoChatPage({Key? key}) : super(key: key);
@override
State<VideoChatPage> createState() => _VideoChatPageState();
}
class _VideoChatPageState extends State<VideoChatPage> {
late final RtcEngine _engine;
///初始化状态
late final Future<bool?> initStatus;
///当前 controller
late VideoViewController currentController;
///是否加入聊天
bool isJoined = false;
/// 记录加入的用户id
Map<int, VideoViewController> remoteControllers = {};
@override
void initState() {
super.initState();
initStatus = _requestPermissionIfNeed().then((value) async {
await _initEngine();
///构建当前用户 currentController
currentController = VideoViewController(
rtcEngine: _engine,
canvas: const VideoCanvas(uid: 0),
);
return true;
}).whenComplete(() => setState(() {}));
}
Future<void> _requestPermissionIfNeed() async {
if (Platform.isMacOS) {
return;
}
await [Permission.microphone, Permission.camera].request();
}
Future<void> _initEngine() async {
//创建 RtcEngine
_engine = createAgoraRtcEngine();
// 初始化 RtcEngine
await _engine.initialize(const RtcEngineContext(
appId: appId,
));
_engine.registerEventHandler(RtcEngineEventHandler(
// 遇到错误
onError: (ErrorCodeType err, String msg) {
if (kDebugMode) {
print('[onError] err: $err, msg: $msg');
}
},
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
// 加入频道成功
setState(() {
isJoined = true;
});
},
onUserJoined: (RtcConnection connection, int rUid, int elapsed) {
// 有用户加入
setState(() {
remoteControllers[rUid] = VideoViewController.remote(
rtcEngine: _engine,
canvas: VideoCanvas(uid: rUid),
connection: const RtcConnection(channelId: cid),
);
});
},
onUserOffline:
(RtcConnection connection, int rUid, UserOfflineReasonType reason) {
// 有用户离线
setState(() {
remoteControllers.remove(rUid);
});
},
onLeaveChannel: (RtcConnection connection, RtcStats stats) {
// 离开频道
setState(() {
isJoined = false;
remoteControllers.clear();
});
},
));
// 打开视频模块支持
await _engine.enableVideo();
// 配置视频编码器,编码视频的尺寸(像素),帧率
await _engine.setVideoEncoderConfiguration(
const VideoEncoderConfiguration(
dimensions: VideoDimensions(width: 640, height: 360),
frameRate: 15,
),
);
await _engine.startPreview();
}
@override
void dispose() {
_engine.leaveChannel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Stack(
children: [
FutureBuilder<bool?>(
future: initStatus,
builder: (context, snap) {
if (snap.data != true) {
return const Center(
child: Text(
"初始化ing",
style: TextStyle(fontSize: 30),
),
);
}
return AgoraVideoView(
controller: currentController,
);
}),
Align(
alignment: Alignment.topLeft,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
///增加点击切换
children: List.of(remoteControllers.entries.map(
(e) => InkWell(
onTap: () {
setState(() {
remoteControllers[e.key] = currentController;
currentController = e.value;
});
},
child: SizedBox(
width: 120,
height: 120,
child: AgoraVideoView(
controller: e.value,
),
),
),
)),
),
),
)
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
// 加入频道
_engine.joinChannel(
token: token,
channelId: cid,
uid: 0,
options: const ChannelMediaOptions(
channelProfile:
ChannelProfileType.channelProfileLiveBroadcasting,
clientRoleType: ClientRoleType.clientRoleBroadcaster,
),
);
},
),
persistentFooterButtons: [
ElevatedButton.icon(
onPressed: () {
_enableVirtualBackground();
},
icon: const Icon(Icons.accessibility_rounded),
label: const Text("虚拟背景")),
ElevatedButton.icon(
onPressed: () {
_engine.setBeautyEffectOptions(
enabled: true,
options: const BeautyOptions(
lighteningContrastLevel:
LighteningContrastLevel.lighteningContrastHigh,
lighteningLevel: .5,
smoothnessLevel: .5,
rednessLevel: .5,
sharpnessLevel: .5,
),
);
//_engine.setRemoteUserSpatialAudioParams();
},
icon: const Icon(Icons.face),
label: const Text("美颜")),
ElevatedButton.icon(
onPressed: () {
_engine.setColorEnhanceOptions(
enabled: true,
options: const ColorEnhanceOptions(
strengthLevel: 6.0, skinProtectLevel: 0.7));
},
icon: const Icon(Icons.color_lens),
label: const Text("增强色彩")),
ElevatedButton.icon(
onPressed: () {
_engine.enableSpatialAudio(true);
},
icon: const Icon(Icons.surround_sound),
label: const Text("空间音效")),
ElevatedButton.icon(
onPressed: () {
_engine.setAudioProfile(
profile: AudioProfileType.audioProfileDefault,
scenario: AudioScenarioType.audioScenarioGameStreaming);
_engine
.setAudioEffectPreset(AudioEffectPreset.roomAcousticsKtv);
},
icon: const Icon(Icons.surround_sound),
label: const Text("人声音效")),
]);
}
Future<void> _enableVirtualBackground() async {
ByteData data = await rootBundle.load("assets/bg.jpg");
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
Directory appDocDir = await getApplicationDocumentsDirectory();
String p = path.join(appDocDir.path, 'bg.jpg');
final file = File(p);
if (!(await file.exists())) {
await file.create();
await file.writeAsBytes(bytes);
}
await _engine.enableVirtualBackground(
enabled: true,
backgroundSource: VirtualBackgroundSource(
backgroundSourceType: BackgroundSourceType.backgroundImg,
source: p),
segproperty:
const SegmentationProperty(modelType: SegModelType.segModelAi));
setState(() {});
}
}
06 último
El contenido de este artículo es un complemento de "Múltiples videollamadas basadas en Acoustics Flutter SDK" . El contenido es relativamente simple, pero se puede ver que Acoustics SDK proporciona una implementación de API muy conveniente, especialmente en el procesamiento de sonido. Debido a que el El artículo es limitado, aquí solo se muestra una introducción simple de la API, por lo que se recomienda encarecidamente que pruebe estas API de audio usted mismo. Es realmente interesante. Además, hay muchas escenas y juegos, puede hacer clic aquí para visitar el sitio web oficial para obtener más información.
Los desarrolladores también pueden probar SoundNet SDK para realizar escenarios de interacción de audio y video en tiempo real. Ahora regístrese para obtener una cuenta de Shengwang para descargar el SDK y podrá obtener una cuota de uso gratuita de 10 000 minutos al mes. Si tiene alguna pregunta durante el proceso de desarrollo, puede comunicarse con los ingenieros oficiales en la comunidad de desarrolladores de Shengwang .