Este exemplo pode usar o serviço fitcDemo do Red5, mais preferi criar o meu próprio por necessitar de muitas alterações e novas implementações.
Basicamente é o serviço fitcDemo que vou adicionar algumas funcionalidades novas ao serviço e para isso você precisa saber um pouco de Java ou pelo manos a não básica.
/** * Se você não sabe nada de Java baixe o Zip que conterá toda a biblioteca compilada. */
Vamos começar criando um projeto no Eclipse For Java com o nome de confDemo. conforme imagens abaixo:

Imagem 01:Novo projeto

Imagem 02: Criando o projeto no Java
Agora antes de prosseguir temos que importar a biblioteca do Red5 no projeto. Para isso clique com o botão direito sobre o projeto e vá em Proprietes. Em Java Build Path >> Libraries clique em Add External JARs e selecione Red5.jar que se encontra na raiz da instalação do Red5 e clique em OK.

Figura 03: Importando o JAR
Agora que o projeto esta criado configurado, vamos criar um novo arquivo java e nomeá-lo de Application.java no Package org.red5.confDemo que estenderá org.red5.server.adapter.ApplicationAdapter e implementará org.red5.server.api.service.IPendingServiceCallback.

Figura 04: Nova Classe
O arquivo gerado esta abaixo e
package org.red5.confDemo;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.service.IPendingServiceCall;
import org.red5.server.api.service.IPendingServiceCallback;
public class Application extends ApplicationAdapter implements
IPendingServiceCallback {
@Override
public void resultReceived(IPendingServiceCall call) {
// TODO Auto-generated method stub
}
}
O método resultReceived implementado server para tratar o retorno do Flex em métodos invocados no Java. Criar também uma classe User para definir os dados dos usuários conectados. Esta classe terá apenas campo USER_ID e USER_NOME.
package org.red5.confDemo;
public class User {
public String USER_ID = null;
public String USER_NOME = null;
public User(String USER_ID, String USER_NOME) {
this.USER_ID = USER_ID;
this.USER_NOME = USER_NOME;
}
}
Bom, agora vamos rescrever os seguintes métodos:
- appStart
É invocado quando o primeiro usuário se conectar na aplicação. Ou seja, quando a aplicação for iniciada; - appConnect
Invocado quando um novo usuário se conectar; - disconnect
Invocado quando o usuário sair da aplicação. Neste processo deve se excluir o usuário da lista de conectados; - appJoin
Invocado quando após o usuario ser aceito na conexão.
E criar os seguintes métodos:
- enviarNovosUsuarios
Envia a lista de usuários conectados a todos os usuários conectados; - listaUsuarios
Retorna a lista de usuários que estão conectados. O problema é que na variável users os desconectados ficam como null, então
Abaixo esta toda a classe montada:
package org.red5.confDemo;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import org.red5.server.adapter.*;
import org.red5.server.api.*;
import org.red5.server.api.service.*;
public class Application extends ApplicationAdapter implements
IPendingServiceCallback {
protected HashMap users = new HashMap();
@Override
public boolean appStart(IScope scope) {
return true;
}
@Override
public boolean appConnect(IConnection conn, Object[] params) {
// quem não envia nome, não ganha conexão
if (params.length != 1) {
rejectClient("Sem permissão de acesso ao sistema!");
return false;
}
String username = params[0].toString();
String uid = conn.getClient().getId();
IServiceCapableConnection service = (IServiceCapableConnection) conn;
User user = new User(uid, username);
users.put(uid, user);
service.invoke("listaUsuarios", new Object[] { listaUsuarios() }, this);
enviarNovosUsuarios();
System.out.println("Novo usuario: " + uid);
return true;
}
@Override
public boolean appJoin(IClient client, IScope scope) {
super.appJoin(client, scope);
// envia a lista de usuários conectados a todos os conectados
enviarNovosUsuarios();
return true;
}
@Override
public synchronized void disconnect(IConnection conn, IScope scope) {
// ID da conexão do usuário
String uid = conn.getClient().getId();
// O usuário que desconectou
users.remove(uid);
enviarNovosUsuarios();
System.out.println("Desconectado: " + uid);
super.disconnect(conn, scope);
}
@Override
public void resultReceived(IPendingServiceCall call) {
System.out.println(call);
}
/**
* Envia a lista de usuários conectados a todos os usuarios
*/
protected void enviarNovosUsuarios() {
Object[] params = new Object[] { listaUsuarios() };
ServiceUtils.invokeOnAllConnections(scope, "listaUsuarios", params);
}
/**
* Retorna a lista de usuários sem os campos nulos
*/
protected HashMap listaUsuarios() {
HashMap params = new HashMap();
Integer key = 0;
Set s = users.keySet();
for (Iterator it = s.iterator(); it.hasNext();) {
User value = users.get(it.next());
if (value != null) {
params.put(key, value);
key++;
}
}
return params;
}
}
Baixe aqui os arquivos java:
Agora dentro da pasta Red5/webapps vamos criar uma nova pasta chamada confDemo. Dentro desta pasta criar uma pastas chamada WEB-INF que receberá as bibliotecas e configurações deste serviço. Dentro desta pasta você criará três arquivos:
Agora exporte o seu aplicativo java e deposite dentro da pasta Red5/webapps/confDemo/WEB-INF/lib, reinicia o serviço do Red5. Para isso vá em File >> Export e abrirá a tela abaixo:

Imagem 05: exportando o projeto java
Agora marque os arquivos que devem ser exportados e selecione a pasta a salvar o Jar.

Figura 6: Finalizando a exportação
Clique em Finish e reinicie o serviço do Red5.
/** * Sempre que alterar o jar na pasta lib terás que reiniciar o o serviço do Red5. */
Agora que o serviço esta criado, vamos criar o aplicativo Flex que trabalhará com este serviço. Esta parte já deve ser mais fácil para a maioria dos leitores.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
horizontalAlign="left"
backgroundColor="#f6f6f6"
backgroundGradientColors="[#f6f6f6, #bbbbbb]"
creationComplete="init()"
viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
// Conexão com o Red5
private var netConnection:NetConnection;
// NetStream responsável por apresentar o vídeo
private var netStream_play:NetStream;
// NetStream responsável por publicar o vídeo
private var netStream_publish:NetStream;
// Canal para o Chat
private var sharedObject:SharedObject;
// Componente para apresnetar o vídeo
private var video:Video
// Nome da publicação do vídeo
private var streamingNome:String="publishVideo"
/**
* executa após carregar o aplicativo
*/
private function init():void
{
video=new Video();
video.height=uiCaixaDoVideo.height;
video.width=uiCaixaDoVideo.width;
}
/**
* Inicia a aplicação e faz a conexão
*/
private function conectar():void
{
if ( hostRTMP.text.length < 15 )
{
Alert.show( "URL muito pequena!" )
return;
}
if ( nome.text.length < 3 )
{
Alert.show( "Nome tem que ter mais de 3 caracteres!" )
return;
}
if ( netConnection != null )
netConnection=null;
netConnection=new NetConnection();
netConnection.addEventListener( NetStatusEvent.NET_STATUS, netStatus );
netConnection.addEventListener( AsyncErrorEvent.ASYNC_ERROR, asyncError )
netConnection.connect( hostRTMP.text, nome.text );
netConnection.client=this;
}
/**
* Método que recebe a lista de usuários enviado pleo Red5
*/
public function listaUsuarios( lista:Array ):void
{
datagridUsuarios.dataProvider=lista;
}
/**
* Método que recebe o Status da conexão
*/
private function netStatus( e:NetStatusEvent ):void
{
switch ( e.info.code )
{
case "NetConnection.Connect.Success":
connectado()
viewstack.selectedIndex=1;
break;
case "NetConnection.Connect.Closed":
viewstack.selectedIndex=0;
break;
case "NetConnection.Connect.Rejected":
viewstack.selectedIndex=0;
break;
case "NetConnection.Connect.Failed":
viewstack.selectedIndex=0;
break;
default:
viewstack.selectedIndex=0;
}
}
/**
* Chamado quando deu sucesso na conexão com o Red5
*/
private function connectado():void
{
sharedObject=SharedObject.getRemote( "chat", netConnection.uri, true )
sharedObject.addEventListener( SyncEvent.SYNC, OnSync );
sharedObject.addEventListener( AsyncErrorEvent.ASYNC_ERROR, asyncError );
sharedObject.connect( netConnection );
sharedObject.client=this;
netStream_play=new NetStream( netConnection )
video.attachNetStream( netStream_play );
uiCaixaDoVideo.addChild( video );
netStream_play.play( streamingNome );
}
/**
* Método responsável por tratar os AsyncErrorEvent
*/
private function asyncError( e:AsyncErrorEvent ):void
{
trace( e )
}
/**
* Método responsável por tratar os SyncEvent
*/
private function OnSync( e:SyncEvent ):void
{
trace( e )
}
/**
* Trata o click do Botão Publicar WebCam
*
* Se marcado publica, ao desmarcar para a publicação.
*/
private function publicar():void
{
if ( btPublicar.selected )
{
btPublicar.label="Parar publicação!"
netStream_publish=new NetStream( netConnection );
netStream_publish.attachCamera( Camera.getCamera());
netStream_publish.attachAudio( Microphone.getMicrophone());
// nome que será publicado
netStream_publish.publish( streamingNome );
}
else
{
btPublicar.label="Publicar no servidor RTMP!"
netStream_publish.close()
netStream_publish=null
}
}
/**
* Envia o testo por Chat e limpa o campo.
*/
private function enviarMensagem():void
{
var msg:String="<p><b>" + nome.text + " diz:</b> " + mensagem.text + "</p>";
sharedObject.send( "recebemsg", msg );
mensagem.text='';
}
/**
* Recebe as mensagens postada no Chat
*/
public function recebemsg( msg:String ):void
{
areaMensagem.htmlText+=msg;
areaMensagem.validateNow();
areaMensagem.verticalScrollPosition=areaMensagem.maxVerticalScrollPosition;
}
]]>
</mx:Script>
<mx:ViewStack id="viewstack"
width="100%"
height="100%"
creationPolicy="all">
<mx:VBox width="100%"
height="100%"
verticalAlign="middle"
horizontalAlign="center">
<mx:Form>
<mx:FormItem label="URL do servidor:" fontWeight="bold">
<mx:TextInput id="hostRTMP"
text="rtmp://localhost/confDemo"
width="200"
fontWeight="normal"/>
</mx:FormItem>
<mx:FormItem label="Nome:" fontWeight="bold">
<mx:TextInput id="nome" width="200" fontWeight="normal"/>
</mx:FormItem>
<mx:FormItem>
<mx:Button label="Conectar no Red5" click="conectar()" fontWeight="normal"/>
</mx:FormItem>
</mx:Form>
</mx:VBox>
<mx:VBox width="100%" height="100%">
<mx:HBox width="100%" height="100%">
<mx:VBox height="100%">
<mx:Canvas left="10"
top="85"
width="160"
height="120"
backgroundColor="#000000">
<mx:UIComponent width="100%" height="100%" id="uiCaixaDoVideo"/>
</mx:Canvas>
<mx:Button id="btPublicar"
label="Publicar WebCam"
click="publicar()"
toggle="true"/>
<mx:DataGrid id="datagridUsuarios" width="100%" height="100%">
<mx:columns>
<mx:DataGridColumn headerText="Usuários" dataField="USER_NOME"/>
</mx:columns>
</mx:DataGrid>
</mx:VBox>
<mx:VBox height="100%" width="100%">
<mx:TextArea id="areaMensagem"
width="100%"
height="100%"
borderStyle="none"
alpha="0.63"
editable="false"/>
<mx:HBox width="100%">
<mx:TextInput id="mensagem" width="100%" enter="enviarMensagem()"/>
<mx:Button label="Enviar" click="enviarMensagem()"/>
</mx:HBox>
</mx:VBox>
</mx:HBox>
</mx:VBox>
</mx:ViewStack>
</mx:Application>
Basicamente o funcionamento é o seguinte: Quando clicar o em conectar, é criado uma instancia do NetConnection e enviado junto o nome da pessoa que esta conectando. Assim que a classe que criamos receber esta conexão, ela replica a todas as todas as conexões enviando a lista de usuários conectados. Estalista é recebida pelo método listaUsuarios do Flex.
No Red5 é verificado se foi enviado o nome e e aceita a conexão. Assim que a conexão for aceita, o Flex cria uma instancia do SharedObject e da play no canal publishVideo para quando alguém publicar um vídeo já estar instanciado.
A instancia do SharedObject é responsável pelo chat. para enviar uma mensagem, utiliza-se o método send, passando como parametro a o método que irá receber a resposta e a mensagem.
Quando clicamos em “publicar vídeo!”, uma instancia do NetStream é criada e publicamos no mesmo canal que foi dados play na lista acima.
Abaixo segue o exemplo finalizado, mais para testar terás que possuir um servidor de Red5.
Fonte do aplicativo Flex esta aqui.
O Aplicativo confDemo compilado para ser depositado no Red5 esta aqui.





Olá Alemão ;) (Eduardo) muito bom aqui seu sítio...estou no meus inicios do Flex, Java sim é o meu forte.
Assumo que isto é só um exemplo...uma pequena questão seria como posso fazer com que veja o imagem publicada pelos outros users conectados já que eu só me vejo a mim mesmo ...o sea...o que eu estou publicando.
Não espero por uma solução mais uma pequena ajuda e que direcção tomar para conseguir o desejado.
Muito bom seu trabalho...vou chequear todos dias ;)
Olá Eduardo!
Ótimo post! muito interessante e acredito que vai ajudar bastante gente.
Parabéns
Olá Eduardo, eu fiz tudo certinho como você explicou no post, mas aqui em casa não deu certo. Eu clico em conectar ao servidor Red5 e nada acontece. O que será?
Eduardo tenho outra duvida. Como faço para fazer o stream ao vivo e ao mesmo tempo gravar o vídeo?
@Renan, quando você publica o vídeo em <i>netStream_publish.publish( streamingNome );</i> adicione o termo <b>record</b> como segundo parâmetro:
<i>netStream_publish.publish( streamingNome, "record" );</i>
Veja mais em http://livedocs.adobe.com/flex/3/langref/flash/net/NetStream.html#publish()
Eduardo,
a minha aplicação está acusando InvalidApp quando eu clico em conectar, debuguei e noite que na hora do netStatus ele chega o código de InvalidApp e não há nenhum tratamento para isso, como faço para consertar este problema?
Abraços,
Roberto Mello.
Você esta seguindo todos os passos direitinho?
Bom dia Eduardo,
Parabens pelo trabalho de ajudar a todos!
so uma duvida o video e o chat funcionam normalmente mas o servico da lista de usuarios nao esta aparecendo nada... tenho que fazer algo com o jar? ou somente colocar na pasta WEB-INF/lib ele ja adiciona ao projeto?
Muito obrigado
@Julio, Você esta usando o serviço condDemo? tentasse este <a href="http://code.mxml.com.br/242/confDemo.zip" rel="nofollow">http://code.mxml.com.br/242/confDemo.zip</a>
Boa tarde Eduardo,
tentei sim, uma duvida este arquivo tenho que colocar dentro da pasta raiz do red5 onde tem tambem uma pasta web-inf ou dentro da pasta do projeto confDemo?
Muito obrigado pela ajuda...
@Julio o arquivo confDemo.zip deve ser descompactado na pasta [Red5Install]/webapps/
Boa tarde, achei excepcional seu artigo, muito bom mesmo, a net hj é muito precaria de artigos bons como o seu nesta aréa. Gostaria de saber se tem como enviar uma mensagem para um dos usuarios em especifico, tipo selecionar um usuario conectado e enviar uma mensagem?
Tem como fazer isto? Se tem, você poderia fazer um proximo artigo falando sobre o assunto ne?
@Joiseney Há duas maneiras de fazer isso!
1° Você atráves do netconnection chama o um método remoto atráves do <b>call</b> e no server ao receber este call você envia somente ao usuário que deseja enviar.
2° Eu em chat que envie privado eu envio através do <b>sharedobject.send</b> e passo o ID. Ao receber esta solicitação se o ID estiver nulo, eu mostro a todos, se estiver definido só mostro se o ID for igual ao informado.
// Privado
sharedObject.send('recebemsg', mensagem, paraUsrId)
// Publico
sharedObject.send('recebemsg', mensagem)
public function recebemsg( msg:String, userId:String=null ):void
{
if(userId == null)
{
areaMensagem.htmlText+=msg;
}
else if(userId == UsuarioConectado.userID)
{
areaMensagem.htmlText+=msg;
}
areaMensagem.validateNow();
areaMensagem.verticalScrollPosition=areaMensagem.maxVerticalScrollPosition;
}
Parabens pelo artigo, ta mais objetivo doque a maioria dos tutorias espalhados por ai. Eu estou estudando o Red5 a uma semana e meia, e teria ficado feliz se sua página aparecesse nas pesquizas iniciais, ^_^ mas foi bom reaprender a aprender e implementei uma aplicação com Spring.
Parabens mesmo pelo artigo, mostra como e cada vez mais facil utilizar Flex.
Deixa tirar uma duvida. Com o Flex sabe que o metodo (public function recebemsg) vai receber as novas mensagens do Red5 onde vc fez esta ligacao que nao consigo encontrar?
Ai esta a mágica, o próprio Flex envia isso para o servidor "espalhar".
Então isso é graças ao <em>sharedObject.send( "recebemsg", msg );</em> que envia uma mensagem ao Red5 e o Red5 irá chamar isso em todos os clientes conectados nesta mesma sala.
Veja que podes alterar a qualquer momento o <em>"recebemsg"</em> para qualquer outro nome, desde que alteres o nome da função <em>"public function recebemsg"</em> também.
Obrigado pela resposta.
Nao querendo explorar e ja explorando.
Quanto ao metodo abaixo como que a lista e populado como e feita a ligacao com o Red5?
* Método que recebe a lista de usuários enviado pleo Red5
*/
public function listaUsuarios( lista:Array ):void
{
datagridUsuarios.dataProvider=lista;
}
Outra duvida quanto aos metodos abaixo como vc explictou o appConnect quanto conecta e appJoin quando e aceito a conexao, vc esta chamando enviarNovosUsuarios() nos 2 metodos com isto vc nao esta enviando 2 vezes a lista de usuarios nao seria suficiento somente em appJoin?
@Override
public boolean appConnect(IConnection conn, Object[] params) {
...
service.invoke("listaUsuarios", new Object[] { listaUsuarios() }, this);
enviarNovosUsuarios();
...
}
@Override
public boolean appJoin(IClient client, IScope scope) {
super.appJoin(client, scope);
// envia a lista de usuários conectados a todos os conectados
enviarNovosUsuarios();
return true;
}
@Wemerson Este foi um erro meu. Já alterei o POST.
Normalmenmte sempre deixo no appConnect. Há poucos e bem específicos que não é invocado o appJoin. Nos que não é chamado, os testes com FMS deram mesmos resultados, podendo ser pela versão do Flash Player.
Segui todos os passos que o Eduardo colocou aqui mas nem tão pouco consigo sequer fazer o connect não faz nada simplesmente e se trocar o url de conexão rtmp://localhost/confDemo para utilizar o fitcDemo funciona logo será que me pode ajudar? Muito Obrigado
ola,
eu usei o diretorio do rtmp://localhost/oflaDemo
e o chat funcionou bem, mas nao aparece os usuarios conectados,
fiz como foi passado.
crei o diretorio no servidor red5 C:\Program Files\Red5\webapps\confDemo descompactei o arquivo disponibilizado.
mas nao funciona.
o que esta dando errado.
uma sugestção.
alguem poderia gravar e colocar o passo a passo no youtube.
muito obrigado.
@gabriel Após descompactar é necessário reiniciar o serviço do Red5.
O Serviço do oflaDemo não tem suporte a lista de usuários.