14、构建实时通信与图像处理应用

构建实时通信与图像处理应用

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
  1. 运行应用
    • 启动信令服务器:
$ 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
  1. 定义视图 :在 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'
            }
        ]
    }
});
  1. 配置控制器 :在 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;
  1. 编写原生代码 :在 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;
    }
}
  1. 配置插件 :在 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 技术,我们可以开发出更加丰富和强大的移动应用。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值