Reduzindo mensagens geradas no terminal ao executar aplicações #NCL/#Lua no #Ginga Virtual STB. #TVD

Quem utiliza o Ginga Virtual Set-top Box para desenvolvimento de aplicações NCL/Lua para a TV Digital, sabe que o trabalho de depurar uma aplicação Lua é algo um pouco chato. Primeiro porque, pelo menos até a versão 0.12.4 da máquina virtual (VM), os erros gerados por scripts NCLua não são corretamente exibidos no terminal, como já relatei neste post.

Outro problema é que não temos um depurador por padrão na VM.

Existem alguns depuradores para Lua, mas como a execução do script lua é controlada pelo Ginga, a integração de um depurador pode não ser algo tão simples assim. Com isto, a depuração que normalmente fazemos é na base da função print de Lua.

No entanto, ao executar a aplicação NCL contendo o script NCLua, o DirectFB (API gráfica leve para uso em sistemas sem um servidor X, como no caso dos sistemas embarcados nos Set-top Boxes com Ginga) gera uma quantidade imensa de mensagens que, pra mim, não tem utilidade nenhuma e apenas atrapalham. Isto devido ao fato de que as mensagens que realmente interessam (que usamos para depuração), geradas pelos nossos scripts Lua, ficam perdidas no meio das mensagens do DirectFB.

Para resolver isto, basta incluir a palavra quiet no final do arquivo /usr/local/etc/directfbrc no Ginga Virtual STB. Nem precisa reiniciar a VM. A configuração será lida automaticamente ao executar uma aplicação NCL.

Quem sabe nas próximas versões da VM isto já venha por padrão.

Read more...

Configurando um servidor para envio de email no Moodle

Atualmente muitas instituições têm utilizado servidores de email externos (como do Google) no lugar de instalar, configurar e manter um servidor na sua rede.

No entanto, muitos destes servidores impõem um limite diário para envio de emails. Usando o Moodle, facilmente este limite é atingido (que no caso do Gmail é de 500 emails/dia).

Além disto, o envio de emails usando uma conta do Google tem outras restrições como não aceitar que seja utilizado o email do usuário que acessou o Moodle como remetente da mensagem. Isto pode ser resolvido, mas requer alterações no código fonte do Moodle (pelo menos até a versão 2.2).

Assim, para resolver estes problemas, segue um breve tutorial mostrando como configurar um servidor de email postfix, em um servidor Linux Ubuntu, para realizar o envio de emails a partir do Moodle.

Instalação e Configuração

Instale o postfix. Utilize as opções padrões durante a instalação.

sudo apt-get install postfix

Configure o php para indicar que temos um servidor de email local. Substitua o remetente@meudomio.com pelo email que utilizará como remetente das mensagens.

cd /etc/php5/conf.d/
sudo echo "sendmail_from = remetente@meudomio.com" > mailconfig.ini
sudo echo "sendmail_path = /usr/sbin/sendmail -t -i -f remetente@meudomio.com" >> mailconfig.ini

Observe que nos comandos acima, é incluído o caminho do sendmail, no entanto, tal aplicativo é apenas um wrapper do postfix para fazê-lo funcionar como o sendmail, aceitando os mesmos parâmetros que o sendmail.

Agora vamos alterar algumas configurações do postfix. Para isto, abra o arquivo com o comando abaixo:

sudo pico /etc/postfix/main.cf

Em myhostname, coloque o domínio pelo qual o servidor de email responderá. Em mydestination, não deve haver o nome do seu domínio na lista.

Se o seu domínio estiver nesta lista, ao tentar enviar um email, o postfix verificará se o destinatário possui uma conta de usuário no sistema local. Como este servidor não hospeda as contas de email de fato (ele apenas despachará os emails desejados), isto causará erro e os email's não serão enviados, retornando a mensagem "Recipient address rejected: User unknown in local recipient table". Desta forma, deixe tal variável da seguinte forma:

mydestination = localhost.localdomain, localhost

Configurações no Moodle

Nas configurações de email do Moodle, basta deixar tudo vazio que ele utilizará o servidor de email local.

Testando o envio de email pelo terminal

Para testar o envio de email pelo terminal, execute o comando de exemplo abaixo:

echo "Corpo da mensagem." | mail -s "Assunto" email@destino.com

Se ao tentar enviar o email você receber o erro "postdrop: warning: unable to look up public/pickup: No suck file or directory", isto indica que você está com o sendmail rodando. Então, será preciso finalizar o mesmo e realizar alguns comandos, como mostrado a seguir:

sudo mkfifo /var/spool/postfix/public/pickup
sudo killall -9 sendmail
sudo /etc/init.d/postfix restart

Se o email de teste, usando o comando mostrado anteriormente, não chegar na sua caixa de entrada, verifique se não foi para o Spam. Caso a mensagem não chegue, mesmo não ocorrendo o erro relatado acima, o sendmail pode estar executando no lugar do postfix. Assim, execute os 3 comandos anteriores para matar o sendmail e iniciar o postfix.

Referências

Kyle Goslin's Blog  Server Fault  Data Basically

Read more...

Controle de foco entre aplicação #NCL e aplicação #Lua. #TVD #GingaNCL #in

Uma das grandes dificuldades que alguns desenvolvedores NCL/Lua tem é em alternar o controle de foco entre a aplicação NCL e Lua, para, quando estiver na aplicação NCL, esta controlar o foco, por exemplo, dos itens de um menu, quando o usuário utilizar as setas do controle remoto para navegar por eles. Quando uma aplicação Lua é iniciada, normalmente deseja-se que o controle de foco e captura de teclas passar para ela. Nestes casos, quando a aplicação lua é finalizada, é preciso fazer o controle de foco voltar para a aplicação NCL, para que o usuário continue alternando o foco entre os itens do menu.

Neste artigo vou mostrar como resolver esta questão. Para isto, vamos criar uma aplicação NCL contendo imagens que representarão itens de um menu.  A aplicação terá 3 itens no menu que ficará posicionado verticalmente, no canto superior esquerdo da tela. Quando o usuário utilizar as setas para cima e para baixo no controle remoto, o foco mudará de um item para o outro. Quando ele pressionar enter sobre o primeiro item, uma aplicação Lua será iniciada e um imagem de um botão vermelho será iniciado. A aplicação lua passará a ter o controle de foco, capturando os eventos ocorridos (como pressionamento de teclas) e exibindo isso na tela. Quando o usuário pressionar o botão vermelho, a aplicação Lua será finalizada, voltando para o NCL que passará a controlar o foco novamente.

Bem, vou mostrar apenas os pontos principais. Todo o código pode ser baixado no final do artigo. Para começar, vamos criar as regiões para nossas mídias, com o código a seguir:

<region id="rgLua" width="100%" height="100%" />
<region id="rgVoltar" right="48" top="0" width="48" height="48" />
<region id="rgMenu" left="0" height="100%" width="150">
<region id="rgMenu1" width="164" height="49" left="0" top="10" />
<region id="rgMenu2" width="164" height="49" left="0" top="60" />
<region id="rgMenu3" width="164" height="49" left="0" top="120" />

Agora vamos inserir os descritores para as mídias:

<descriptor id="dLua" region="rgLua" focusIndex="0" />
<descriptor id="dMenu1" region="rgMenu1" focusIndex="1" moveDown="2" moveUp="3" />
<descriptor id="dMenu2" region="rgMenu2" focusIndex="2" moveDown="3" moveUp="1" />
<descriptor id="dMenu3" region="rgMenu3" focusIndex="3" moveDown="1" moveUp="2" />
<descriptor id="dVoltar" region="rgVoltar" />

Para permitir a navegação entre os itens do menu, é preciso definir um focusIndex para cada um. Este é um valor inteiro que funciona como um tabindex do HTML, definindo a ordem dos itens. Por meio das propriedades moveDown, moveUp, moveLeft e moveRight (estas duas últimas não utilizadas aqui) podemos definir para qual item do menu o foco irá quando o usuário pressionar, respectivamente, as setas para baixo, para cima, para a esquerda e para a direita.

Um detalhe importante, para fazer a troca do controle de foco entre a aplicação NCL e a Lua funcionar, é definir um focusIndex para a mídia Lua. Neste caso, utilizei o valor 0 (zero).

O botão voltar não precisa de focusIndex pois ele não receberá o foco. Quando ele for iniciado, independente de onde o foco esteja, se o usuário pressionar o vermelho, a aplicação Lua será finalizada.

Para o sincronismo das mídias vamos precisar de alguns conectores (que não mostrarei o código por serem básicos e podem ser vistos no arquivo para download) sendo os primeiros: onBeginStartN, onBeginStopN, onEndStop, onEndStartNStop. Se você está criando a aplicação do zero, sugiro utilizar o plugin NCLEclipse que já permite automaticamente criar um arquivo contendo todos estes conectores básicos e mais alguns.

Precisaremos ainda de um conector onKeySelectionStop. O mesmo define que, quando uma tecla for pressionada, será dado stop em uma determinada mídia.

Ainda precisaremos de um conector onSelectionStart. Este define que, quando um item em foco for acionado com a tecla OK (ENTER), uma mídia será iniciada.

Para finalizar, precisaremos ainda de conectores onBeginSet (que, quando uma mídia iniciar, seta valor para uma propriedade de qualquer mídia) e um onEndSet (que, quando uma mídia finalizar, seta valor para uma propriedade de qualquer mídia).

Incluídos os conectores, vamos inserir a porta para iniciar a primeira mídia e as mídias:

<port id="pInicial" component="menu1"/>

<media id="menu1" src="media/menu1.png" descriptor="dMenu1"/>
<media id="menu2" src="media/menu2.png" descriptor="dMenu2"/>
<media id="menu3" src="media/menu3.png" descriptor="dMenu3"/>
<media id="lua"   src="main.lua" descriptor="dLua" />
<media id="voltar" src="media/red.png" descriptor="dVoltar" />

Agora, para permitir a alternância de foco entre a aplicação NCL e a Lua, precisamos incluir uma mídia do tipo application/x-ginga-settings. Uma mídia deste tipo possui variáveis de ambiente reservadas. Uma destas propriedades é a service.currentKeyMaster. Segundo a norma ABNT NBR 15606-2, tal propriedade armazena:

o identificador (id) do elemento que detém o controle das chaves de navegação; se o elemento não estiver sendo apresentado ou não estiver pausado, o controle é do formatador.

Desta forma, vamos inserir uma mídia deste tipo para poder controlar o valor da propriedade service.currentKeyMaster:

<media id="settings" type="application/x-ginga-settings">
<property name="service.currentKeyMaster" value=""/>
</media>

O valor da propriedade está vazio para definir que o controle de foco inicialmente será da aplicação NCL.

Agora vamos incluir os links para controle da navegação na aplicação inteira. Este são links básicos, não tendo nenhuma relação com o controle de foco, e o código está todo comentado:

<!--Quando iniciar o primeiro item de menu, inicia os outros-->
<link xconnector="onBeginStartN">
    <bind role="onBegin" component="menu1" />
    <bind role="start" component="menu2" />
    <bind role="start" component="menu3" />
</link>

<!--Ao pressionar ENTER no menu1, inicia o lua-->
<link xconnector="onSelectionStart">
    <bind role="onSelection" component="menu1" />
    <bind role="start" component="lua" />
</link>

<!--Quando iniciar o lua, inicia o botão vermelho (que permite voltar ao menu)-->
<link xconnector="onBeginStartN">
    <bind role="onBegin" component="lua" />
    <bind role="start" component="voltar" />
</link>

<!--Quando iniciar o lua, para os menus-->
<link xconnector="onBeginStopN">
    <bind role="onBegin" component="lua" />
    <bind role="stop" component="menu1" />
    <bind role="stop" component="menu2" />
    <bind role="stop" component="menu3" />
</link>

<!--Quando pressionar RED, para o lua e volta ao menu-->
<link xconnector="onKeySelectionStop">
    <bind role="onSelection" component="voltar">
        <bindParam name="key" value="RED"/>
    </bind>
    <bind role="stop" component="lua" />
</link>

<!--Quando o lua finalizar, inicia o menu1 (outro link iniciará os outros menus)  e para o botão voltar-->
<link xconnector="onEndStartNStop">
    <bind role="onEnd" component="lua" />
    <bind role="start" component="menu1" />
    <bind role="stop" component="voltar" />
</link> 

Agora sim, vamos incluir os links responsáveis pela alternância do controle de foco entre a aplicação NCL e a Lua. Como declaramos a mídia settings com a propriedade service.currentKeyMaster alteriormente, vamos incluir um link que permitirá, ao iniciar a aplicação Lua, passar o controle de foco para ela:

<link xconnector="onBeginSet">
<bind role="onBegin" component="lua" />
    <bind role="set" component="settings" interface="service.currentKeyMaster">
        <bindParam name="value" value="lua"/>
    </bind>
</link>

Note que, quando a mídia Lua iniciar, o valor da propriedade service.currentKeyMaster  da mídia settings será alterado para "lua", que é o id da mídia Lua que controlará o foco.

Quando a mídia Lua for finalizada, precisaremos voltar o controle de foco para a aplicação NCL utilizando outro link. Para isto, apenas setamos o valor da propriedade service.currentKeyMaster para vazio, como mostrado a seguir:

<link xconnector="onEndSet">
    <bind role="onEnd" component="lua" />
    <bind role="set" component="settings" interface="service.currentKeyMaster">
        <bindParam name="value" value=""/>
    </bind>
</link>

Agora só falta inserir o código para o arquivo main.lua, que simplesmente interceptará os eventos gerados pela aplicação (como o pressionamento de teclas) e mostrará tais dados na tela. Segue o código:

function handler(evt)
    local s = ""
    for k, v in pairs(evt) do
        print("\t\t",k,v)
        s = s .. k .. "=" .. v .. "; "
    end

    canvas:attrFont("vera", 14)
    canvas:attrColor(255, 255, 255, 255)
    local largura, altura = canvas:attrSize()
    canvas:drawRect("fill", 0, 0, largura, altura)
    canvas:attrColor(255, 0, 0, 255)
    canvas:drawText(10,10,s)
    canvas:flush()
end

event.register(handler)

Então é isto aí. Só lembrando, que a alternância de controle de foco só funciona se definirmos um número para o focusIndex do descritor da mídia Lua.

Read more...

Redimensionando e restaurando um vídeo em aplicação #NCL - Parte 2. #TVD #in

No artigo anterior, mostrei como redimensionar um vídeo e restaurar seu tamanho original usando apenas NCL. Como foi mostrado lá, a forma como tal recurso foi implementado é um pouco estático. Se você reduzir um vídeo para 50%, para restaurá-lo para o tamanho original, precisará alterar suas dimensões para 200% (de acordo com a regra de 3 apresentada no artigo anterior). No entanto, se resolver colocar um percentual diferente para reduzir o vídeo, precisará recalcular o percentual utilizado para restaurar seu tamanho original e alterar o documento NCL inserindo os novos valores.

Vou mostrar neste artigo como tornar a restauração do vídeo dinâmica, usando novamente apenas NCL.

Vamos usar a mesma lógica da aplicação anterior, contendo um vídeo que, após 5 segundos de iniciado, será redimensionado e apresentará uma imagem de um botão vermelho. Quando o usuário acionar o respectivo botão no controle remoto, o vídeo volta ao tamanho original. Desta forma, você pode utilizar o código da aplicação anterior como base. Utilizaremos os mesmos conectores, sem alterar, adicionar nem remover nenhum. O que mudará será nos links.

Bem, a lógica para tornar a restauração do vídeo dinâmica será a seguinte: quando o vídeo iniciar, vamos obter suas dimensões e guardá-las em uma variável. Após o vídeo ser redimensionado, quando o usuário acionar o botão vermelho para restaurar o vídeo, as dimensões serão obtidas desta variável e setadas para a propriedade bounds do vídeo.

Para isto, vamos inserir uma nova mídia do tipo "application/x-ginga-settings", que, segundo a norma ABNT NBR 15606-2:

suas propriedades são variáveis globais definidas pelo autor do documento ou variáveis de ambiente reservadas, que podem ser manipuladas pelo processamento do documento NCL.

Desta forma, vamos criar uma variável chamada bounds, em uma mídia deste tipo, para poder guardar as dimensões originais do vídeo. Assim, declare a mídia como mostrado a seguir:

<media id=&quot;settings&quot; type=&quot;application/x-ginga-settings&quot;>
  <property name=&quot;bounds&quot; />
</media>

Agora, precisaremos incluir um novo link onBeginSet para, quando o vídeo iniciar, guardar o valor da sua propriedade bounds na propriedade bounds da mídia settings (adicionada anteriormente). Com isto, quando desejarmos restaurar o vídeo, podemos pegar suas dimensões originais na propriedade bounds da mídia settings. Segue o código do link:

<link xconnector=&quot;onBeginSet&quot;>
  <bind role=&quot;onBegin&quot; component=&quot;video&quot; />
  <bind role=&quot;get&quot; component=&quot;video&quot; interface=&quot;bounds&quot;/>
  <bind role=&quot;set&quot; component=&quot;settings&quot; interface=&quot;bounds&quot;>
    <bindParam name=&quot;var&quot; value=&quot;$get&quot;/>
  </bind>
</link>

Note que estamos utilizando um papel "get" (no atributo role da tag bind) que não foi declarado no conector (já existente na aplicação anterior). O papel get é implicito em conectores que tenham o papel set.

A linha  utiliza o papel get para obter o valor da propriedade bounds do vídeo. Tal valor é armazenado em uma variável com o mesmo nome do papel (variável $get). Na tag bind seguinte, o valor desta variável é obtido e atribuído à propriedade bounds da mídia settings.

Na verdade, para conectores que possuem o papel set, este papel que permite obter o valor de uma propriedade pode ter qualquer nome, por exemplo, "ler". O nome do papel é que vai definir o nome da variável que armazenará o valor lido.

Com o uso dos papéis get e set, podemos obter o valor de uma propriedade de uma mídia e atribuir tal valor a outra propriedade de qualquer mídia. Esta atribuição não é direta, como podem ver no código. A variável $get é utilizada como uma variável intermediária. Logo, tal link poderia ser representado, de forma procedural, utilizando o seguinte pseudo-código:

$get = video.bounds;
settings.bounds = $get;

Bem, pra finalizar, falta permitirmos que o vídeo volte ao tamanho original quando o usuário pressionar o botão vermelho (o link onBeginSet para reduzir o vídeo já existia na aplicação anterior). Para isto, precisaremos alterar o link onKeySelectionStopSet para o código seguinte:

<link xconnector=&quot;onKeySelectionStopSet&quot;>
  <bind role=&quot;onSelection&quot; component=&quot;botao&quot;>
    <bindParam name=&quot;key&quot; value=&quot;RED&quot;/>
  </bind>
  <bind role=&quot;get&quot; component=&quot;settings&quot; interface=&quot;bounds&quot;/>
  <bind role=&quot;set&quot; component=&quot;video&quot; interface=&quot;bounds&quot;>
    <bindParam name=&quot;var&quot; value=&quot;$get&quot;/>
  </bind>
  <bind role=&quot;stop&quot; component=&quot;botao&quot; />
</link>

Tal link utiliza a mesma lógica do anterior: utiliza os papéis get e set para pegar o valor da propriedade bounds da mídia settings (contendo as dimensões originais do vídeo) e atribuir de volta à propriedade bounds do vídeo.

Então é isso. Finalizamos as 2 partes do artigo, deixando dinâmico a restauração das dimensões do vídeo usando apenas NCL. No link a seguir você pode baixar o código completo da aplicação. Até o próximo.

Read more...

Redimensionando e restaurando um vídeo em aplicação #NCL - Parte 1. #TVD #in

Quando se reduz um objeto, como um vídeo, em uma aplicação NCL (ou qualquer outra) para 50%, por exemplo, para voltar ao tamanho original, não adianta setar as propriedades width e height para 100%. Isto apenas fará com que as dimensões do vídeo sejam alteradas para 100% do valor atual.

Se o vídeo tinha 400x400 e foi reduzido para 50%, seu tamanho atual é 200x200. Assim, 100% será referente ao tamanho atual. Assim, alterar as dimensões para 100% não fará efeito nenhum sobre o tamanho do vídeo, pois 100% de 200x200 é 200x200 :).

Para voltar o vídeo ao tamanho anterior de 400x400, teremos que alterar suas dimensões para 200% do valor atual. Para encontrar tal percentual, pode-se resolver a regra de 3 abaixo:

100% - dimensao_atual x - dimensao_original

O cálculo deve ser feito para a largura e depois para a altura. Usando tal fórmula, um vídeo que foi reduzido para 50%, para voltar ao tamanho original terá que ter sua dimensão alterada para 200%.

Então, vamos à construção da aplicação. Vou explicar apenas o fundamental (a aplicação completa está disponível para download no final do artigo). Nossa aplicação terá um vídeo, que após 5 segundos de iniciado, será redimensionado para 50% e apresentará um botão vermelho. Quando o usuário pressionar o respectivo botão do controle remoto, o vídeo voltará ao tamanho original.

Para isto, precisamos de um vídeo e uma imagem para representar o botão vermelho do controle. Inclua as mídias na aplicação (tags region's, descriptor's e media's) e uma porta para o vídeo.

No vídeo, vamos incluir uma âncora quer marcará os 5 segundos de início do mesmo e vamos publicar a propriedade bounds (que define em um atributo só, o top, left, width e height da mídia) para permitir que alteremos ela por meio de um link. Segue código da mídia do vídeo:

<media id="video" src="media/video.avi" descriptor="dVideo">
    <property name="bounds"/>
    <area id="a1" begin="5s"/>
</media>

Agora vamos precisar criar alguns conectores. O onBeginStart será utilizado para, quando uma mídia iniciar, iniciar dar start em outra. Veja código do conector abaixo:

<causalConnector id="onBeginStart">
    <simpleCondition role="onBegin"/>
    <simpleAction role="start"/>
</causalConnector>

O conector onBeginSet será usado para, quando uma mídia iniciar, alterar uma propriedade de outra. Segue código do conector:

<causalConnector id="onBeginSet">
    <connectorParam name="var"/>
    <simpleCondition role="onBegin"/>
    <simpleAction role="set" value="$var"/>
</causalConnector>

A variável (connectorParam)  "var" é usada para permitir, no link a ser adicionado posteriormente, especificar qual valor será setado para a propriedade lá especificada (no nosso caso, será a propriedade bounds do vídeo).

Agora vamos adicionar um conector onKeySelectionStopSet para, quando o usuário pressionar um botão, parar uma mídia e setar uma propriedade de outra. Segue código:

<causalConnector id="onKeySelectionStopSet">
    <connectorParam name="var"/>
    <connectorParam name="key"/>
    <simpleCondition role="onSelection" key="$key" />
    <compoundAction operator="seq">
        <simpleAction role="set" value="$var"/>
        <simpleAction role="stop"/>
    </compoundAction>
</causalConnector>

A variável "var" é usada com a mesma finalidade do conector anterior. A variável key é usado para, somente no link, especificar qual tecla iniciará as ações do conector. Desta forma, o conector fica mais reutilizável.

Bem, agora vamos para os links. O primeiro link iniciará a imagem do botão vermelho quando a âncora de 5 segundos do vídeo iniciar, usando o conector onBeginStart criado anteriormente:

<link xconnector="onBeginStart">
    <bind role="onBegin" component="video" interface="a1"/>
    <bind role="start" component="botao" />
</link>

Agora, vamos inserir um link para, quando a âncora de 5 segundos do vídeo iniciar, alterar o tamanho do mesmo para 50%:

<link xconnector="onBeginSet">
    <bind role="onBegin" component="video" interface="a1"/>
    <bind role="set" component="video" interface="bounds">
        <bindParam name="var" value="0,0,50%,50%"/>
    </bind>
</link>

Por fim, vamos inserir um link para, quando o usuário pressionar o botão vermelho, parar a imagem e restaurar o tamanho do vídeo. Como reduzimos ele para 50%, para voltar ao normal precisamos alterar suas dimensões para 200%. Segue código do link:

<link xconnector="onKeySelectionStopSet">
    <bind role="onSelection" component="botao">
        <bindParam name="key" value="RED"/>
    </bind>

    <bind role="set" component="video" interface="bounds">
        <bindParam name="var" value="0,0,200%,200%"/>
    </bind>
    <bind role="stop" component="botao" />
 </link>

Bem, agora é rodar e testar. Ao iniciar a aplicação, depois de 5 segundos o vídeo é redimensionando e o botão vermelho aparece. Quando você pressionar o botão, o vídeo volta ao tamanho anterior.

O código é bem simples, no entanto, estático. Se você resolver alterar os valores de redimensionamento do vídeo, precisará usar a regra de 3 mostrada no início do artigo para descobrir qual o valor percentual que precisará aplicar para voltar o vídeo ao tamanho original.

Na segunda parte do artigo, mostrarei como tornar isto dinâmico, usando apenas NCL. Até lá.

Read more...