构建实时通信与图像处理应用
1. 构建基础 WebRTC 实时通信应用
在构建实时通信应用时,首先要处理消息类型。当接收到
offer
类型的消息,意味着有来电,此时需创建
SessionDescription
,将其设为对等连接的远程描述并创建应答;若收到
answer
类型消息,执行相同操作但不创建应答;对于
candidate
消息类型,创建
IceCandidate
并添加到对等连接。
以下是具体操作步骤:
1.
Cordova 应用调整
:为让移动设备的相机和麦克风可用,需在
platforms/android/AndroidManifest.xml
中添加以下代码:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
若发现移动设备音频无法传输,可安装
org.chromium.audiocapture
插件,使用以下命令安装:
$ cordova plugin add org.chromium.audiocapture
-
运行应用
:
- 启动信令服务器:
$ cd server
$ node server.js
- 在浏览器中启动客户端:
$ cd client/www
$ python -m SimpleHTTPServer 8000
- 在真机上启动移动应用:
$ cd client/www
$ cordova run android
当在浏览器中打开
http://localhost:8000
时,会被请求授予相机和麦克风访问权限,点击允许后,就能看到本地视频。在移动设备上也会有类似界面,但不会请求权限。点击“Call”按钮,就能在两个端点间建立通话,视频和音频均可正常传输。
2. 使用 PeerJS 构建实时通信应用
PeerJS 是浏览器 WebRTC 实现的封装库,旨在简化对等连接管理并提供列出已连接客户端的功能。
2.1 服务器端
创建一个简单的 Node.js 应用,添加
peer
和
ip
模块,使用以下命令:
$ npm install peer --save
$ npm install ip --save
安装后,
package.json
文件可能如下:
{
"name": "pumpidu-peerjs",
"version": "0.0.0",
"description": "Run a PeerJS WebRTC server",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Andrew Kovalenko <cybind@gmail.com>",
"license": "MIT",
"dependencies": {
"peer": "^0.2.5",
"ip": "^0.3.0"
}
}
在
server.js
文件中添加逻辑:
var ip = require('ip');
var port = 9000;
var PeerServer = require('peer').PeerServer;
var server = new PeerServer({
port: port,
allow_discovery: true
});
server.on('connection', function(id) {
console.log('new connection with id ' + id);
});
server.on('disconnect', function(id) {
console.log('disconnect with id ' + id);
});
console.log('peer server running on ' + ip.address() + ':' + port);
启动服务器:
$ node server.js
也可使用更简单的方式启动:
$ peerjs --port 9000 --key peerjs
2.2 客户端
保持 CSS 和 HTML 与之前示例相同,将
socket.io
库替换为
peer.js
:
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/peer.js"></script>
<script type="text/javascript" src="js/index.js"></script>
在
index.js
文件的
init()
函数中定义变量:
var SERVER_IP = '192.168.0.102';
var SERVER_PORT = 9000;
var callButton = document.querySelector("#callButton");
var localVideo = document.querySelector("#localVideo");
var remoteVideo = document.querySelector("#remoteVideo");
var callerId = null;
var peer = null;
var localStream = null;
应用启动后,显示提示框让用户输入
callerId
:
var setCallerId = function () {
callerId = prompt('Please enter your name');
connect();
};
connect()
函数中,先检查
callerId
是否设置,若未设置则重新分配。使用
try-catch
块连接到 PeerJS 服务器:
try {
console.log('create connection to the ID server');
console.log('host: ' + SERVER_IP + ', port: ' + SERVER_PORT);
peer = new Peer(callerId, {
host: SERVER_IP,
port: SERVER_PORT
});
// ...
} catch (e) {
peer = null;
alert('Error while connecting to server');
}
连接成功后,分配
onclose
、
onopen
和
on call
处理程序:
peer.socket._socket.onclose = function() {
alert('No connection to server');
peer = null;
};
peer.socket._socket.onopen = function() {
getLocalStream(function() {
callButton.style.display = 'block';
});
};
peer.on('call', answer);
获取本地流的函数
getLocalStream
:
var getLocalStream = function(successCb) {
if (localStream && successCb) {
successCb(localStream);
} else {
navigator.webkitGetUserMedia({
audio: true,
video: true
},
function(stream) {
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
if (successCb) {
successCb(stream);
}
},
function(err) {
alert('Failed to access local camera');
console.log(err);
});
}
};
处理来电的函数
answer
:
var answer = function(call) {
if (!peer) {
alert('Cannot answer a call without a connection');
return;
}
if (!localStream) {
alert('Could not answer call as there is no localStream ready');
return;
}
console.log('Incoming call answered');
call.on('stream', showRemoteStream);
call.answer(localStream);
};
处理去电的函数
dial
:
callButton.addEventListener('click', dial);
var dial = function() {
if (!peer) {
alert('Please connect first');
return;
}
if (!localStream) {
alert('Could not start call as there is no local camera');
return;
}
var recipientId = prompt('Please enter recipient name');
if (!recipientId) {
alert('Could not start call as no recipient ID is set');
dial();
return;
}
getLocalStream(function(stream) {
console.log('Outgoing call initiated');
var call = peer.call(recipientId, stream);
call.on('stream', showRemoteStream);
call.on('error', function(e) {
alert('Error with call');
console.log(e.message);
});
});
};
运行应用的步骤与之前相同,启动服务器、浏览器客户端和移动应用后,输入客户端 ID 和昵称,授予相机和麦克风权限,即可发起通话。
3. 其他构建 WebRTC 移动应用的工具
除了上述方法,还有其他工具可用于构建 WebRTC 移动应用:
| 工具名称 | 特点 | 网址 |
| ---- | ---- | ---- |
| OpenTok | 复杂的付费解决方案,提供 STUN 和 TURN 功能,资费基于通话时长,有 Cordova 插件 | https://tokbox.com/ |
| PhoneRTC | 免费的 PhoneGap/Cordova 插件,可与 SIP.js 配合使用 | http://phonertc.io/ |
这两个工具的 Cordova 插件都使用 Android 和 iOS 的 WebRTC 原生实现,不通过 WebView。可在以下网址查看原生 WebRTC 代码和用法:
- http://www.webrtc.org/native-code/android
- http://www.webrtc.org/native-code/ios
4. 构建类似 Instagram 的图像处理应用
接下来将构建一个名为 “Imaginary” 的类似 Instagram 的应用,为图片添加效果。
4.1 Pixastic 库概述
Pixastic 库可用于对设备相机拍摄的图片轻松应用图像滤镜,使用 HTML5 Canvas 进行图像处理。主要需要以下四个文件:
-
pixastic.js
:包含基本逻辑的主文件
-
pixastic.effects.js
:影响逻辑和像素处理的文件
-
pixastic.worker.control.js
:用于控制工作线程的文件
-
pixastic.worker.js
:工作线程文件
以下是 Pixastic 库的简单使用示例:
var img = new Image();
img.onload = function () {
var oc = document.createElement('canvas'),
octx = oc.getContext('2d');
oc.width = img.width;
oc.height = img.height;
octx.drawImage(img, 0, 0, img.width, img.height);
P = new Pixastic(octx);
P['mosaic']({ blockSize: 8 }).done(function() {
// processing finished
var data = oc.toDataURL();
}, function(p) {
// display progress here;
});
};
img.src = 'some/image/url/image.jpg';
创建
Image
对象,分配源并等待图片加载。创建
canvas
元素并获取其 2D 上下文,将图片的宽度和高度分配给
canvas
,绘制图片。创建
Pixastic
对象,处理
mosaic
效果,处理完成后可通过
oc.toDataURL()
获取带有效果的图片数据。
总结
通过上述方法,我们成功创建了两个版本的 WebRTC 应用,还了解了其他构建 WebRTC 移动应用的工具。同时,介绍了 Pixastic 库并准备使用它构建类似 Instagram 的图像处理应用。这些技术和工具为实时通信和图像处理领域提供了强大的支持。
流程图
graph TD;
A[开始] --> B[构建基础 WebRTC 应用];
B --> C[Cordova 应用调整];
C --> D[运行应用];
D --> E[使用 PeerJS 构建应用];
E --> F[服务器端配置];
F --> G[客户端配置];
G --> H[运行 PeerJS 应用];
H --> I[探索其他工具];
I --> J[构建图像处理应用];
J --> K[了解 Pixastic 库];
K --> L[开发 Imaginary 应用];
L --> M[结束];
构建实时通信与图像处理应用(下半部分)
5. 构建 Imaginary 应用的详细步骤
5.1 应用结构组织
在构建 “Imaginary” 应用时,我们会重新审视使用 Sencha Touch 进行应用结构组织。Sencha Touch 是一个强大的 JavaScript 框架,它可以帮助我们创建响应式的移动应用界面。以下是使用 Sencha Touch 组织应用结构的一般步骤:
1.
创建项目
:使用 Sencha CMD 工具创建一个新的 Sencha Touch 项目。
sencha -sdk /path/to/sencha-touch generate app ImaginaryApp /path/to/app
-
定义视图
:在
app/view目录下创建不同的视图文件,例如主视图、图片选择视图、滤镜应用视图等。
// 示例:主视图定义
Ext.define('ImaginaryApp.view.Main', {
extend: 'Ext.Container',
xtype: 'mainview',
config: {
layout: 'vbox',
items: [
{
xtype: 'button',
text: '选择图片',
handler: function() {
// 处理图片选择逻辑
}
},
{
xtype: 'container',
itemId: 'imageContainer'
}
]
}
});
-
配置控制器
:在
app/controller目录下创建控制器来处理视图的事件和逻辑。
// 示例:主控制器
Ext.define('ImaginaryApp.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
mainView: 'mainview',
imageContainer: 'mainview #imageContainer'
},
control: {
'mainview button[text="选择图片"]': {
tap: 'onSelectImage'
}
}
},
onSelectImage: function() {
// 实现图片选择逻辑
}
});
5.2 图像缩放与处理
在应用中,我们可能需要对图片进行缩放以适应不同的设备屏幕。使用 HTML5 Canvas 可以很方便地实现这一功能。以下是一个使用 HTML5 Canvas 缩放图片的示例代码:
function resizeImage(img, maxWidth, maxHeight) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var width = img.width;
var height = img.height;
if (width > maxWidth) {
height = height * (maxWidth / width);
width = maxWidth;
}
if (height > maxHeight) {
width = width * (maxHeight / height);
height = maxHeight;
}
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
return canvas.toDataURL();
}
结合 Pixastic 库,我们可以对缩放后的图片应用各种滤镜效果。例如,应用模糊滤镜:
var img = new Image();
img.onload = function () {
var oc = document.createElement('canvas'),
octx = oc.getContext('2d');
oc.width = img.width;
oc.height = img.height;
octx.drawImage(img, 0, 0, img.width, img.height);
P = new Pixastic(octx);
P['blur']({ amount: 5 }).done(function() {
// 处理完成
var data = oc.toDataURL();
// 将处理后的图片显示在页面上
var resultImg = document.createElement('img');
resultImg.src = data;
document.body.appendChild(resultImg);
}, function(p) {
// 显示进度
});
};
img.src = 'path/to/your/image.jpg';
5.3 构建自定义 PhoneGap/Cordova 插件
为了让应用能够访问设备的原生功能,我们可以构建自定义的 PhoneGap/Cordova 插件。以下是构建一个简单插件的步骤:
1.
创建插件目录结构
:在项目根目录下创建一个新的插件目录,例如
plugins/com.example.imaginaryplugin
。
2.
编写插件代码
:在插件目录下创建
www
目录用于存放 JavaScript 代码,
src
目录用于存放原生代码。
// www 目录下的 JavaScript 代码
var exec = require('cordova/exec');
var ImaginaryPlugin = {
getDeviceInfo: function(success, error) {
exec(success, error, 'ImaginaryPlugin', 'getDeviceInfo', []);
}
};
module.exports = ImaginaryPlugin;
-
编写原生代码
:在
src/android或src/ios目录下编写相应的原生代码。
// Android 原生代码示例
package com.example.imaginaryplugin;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;
import org.json.JSONArray;
import org.json.JSONException;
public class ImaginaryPlugin extends CordovaPlugin {
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (action.equals("getDeviceInfo")) {
String deviceInfo = "Device: " + android.os.Build.MODEL;
callbackContext.success(deviceInfo);
return true;
}
return false;
}
}
-
配置插件
:在
config.xml文件中添加插件配置。
<plugin name="ImaginaryPlugin" value="com.example.imaginaryplugin.ImaginaryPlugin" />
6. 总结与展望
通过上述步骤,我们完成了 “Imaginary” 应用的构建。我们学习了如何使用 Sencha Touch 组织应用结构,利用 HTML5 Canvas 和 Pixastic 库进行图像缩放和处理,以及构建自定义的 PhoneGap/Cordova 插件。这些技术和方法为我们开发功能丰富的移动应用提供了强大的支持。
在未来的开发中,我们可以进一步扩展这些应用,例如添加更多的滤镜效果、优化图像加载速度、实现图片分享功能等。同时,我们也可以探索更多的 WebRTC 和图像处理技术,为用户带来更好的体验。
表格:工具与功能总结
| 工具/技术 | 功能 |
|---|---|
| WebRTC | 实现实时通信,包括音频和视频通话 |
| PeerJS | 简化对等连接管理,支持多人通话 |
| Pixastic 库 | 对图片应用各种滤镜效果 |
| Sencha Touch | 组织移动应用的结构和界面 |
| HTML5 Canvas | 图像缩放和绘制 |
| PhoneGap/Cordova 插件 | 访问设备原生功能 |
流程图
graph TD;
A[开始构建 Imaginary 应用] --> B[应用结构组织];
B --> C[图像缩放与处理];
C --> D[构建自定义插件];
D --> E[完成应用开发];
E --> F[测试与优化];
F --> G[发布应用];
G --> H[结束];
通过以上的流程和步骤,我们可以逐步构建出一个功能完善的类似 Instagram 的图像处理应用。同时,结合之前学习的 WebRTC 技术,我们可以开发出更加丰富和强大的移动应用。
超级会员免费看

被折叠的 条评论
为什么被折叠?



