<para>Um aspecto importante do &MCOP; é a <emphasis>linguagem de descrição de interface</emphasis>, &IDL;, na qual muitas interfaces e <acronym>API</acronym>s do &arts; são definidas de uma maneira independente de linguagem. </para>
<para>Para usar interfaces &IDL; a partir do C++, é pelo compilador &IDL; para código C++. Ao implementar uma interface, você deriva a partir da classe esqueleto que o compilador &IDL; gerou. Ao usar uma interface, você faz isso como se estivesse usando um envólucro. Desta maneira, o &MCOP; pode usar um protocolo se o objeto com que você está falando não é local - você obtém transparência de rede. </para>
<para>Este capítulo busca descrever os recursos básicos do modelo de objeto que resulta a partir do uso do &MCOP;, o protocolo, como usar o &MCOP; em C++ (ligação com a linguagem), e assim por diante. </para>
<para>Muitos dos serviços fornecidos pelo &arts;, como os módulos e o servidor de som, são definidos em termos de <acronym>interfaces</acronym>. Interfaces são especificadas em um formato independente de linguagem: &IDL;. </para>
<para>Isto permite que muitos dos detalhes da implementação como o formato de fluxos de dados multimídia, transparência de rede, e dependências de linguagem de programação, sejam ocultas a partir da especificação da interface. Uma ferramenta, o &mcopidl;, traduz a definição de interface para uma linguagem de programação específica (atualmente somente o C++ é suportado). </para>
<para>A ferramenta gera uma classe esqueleto com todo código correspondente e funcionalidade básica. Você deriva a partir desta classe para implementar os recursos que deseja. </para>
<para>Interfaces &IDL; são definidas de maneira bem semelhante às classes C++ ou estruturas C, apesar de com algumas restrições. Como no C++, interfaces pode ter subclasses de outras interfaces usando herança. Definições de interface podem incluir três coisas: fluxos, atributos e métodos. </para>
<para>Fluxos possuem uma direção definida em referência ao módulo, como indicado pelos qualificadores obrigatórios in ou out. O argumento type define o tipo de dado, que pode ser qualquer um dos tipos descritos mais tarde pelos atributos (nem todos são atualmente suportados). Muitos módulos usam o tipo de fluxo audio, que é um apelido para flutuante uma vez que este é o formato de dados interno para fluxo de áudio. Fluxo múltiplos do mesmo tipo podem ser definidos na mesma definição usando nomes separados por vírgulas. </para>
<para>Fluxos são por padrão síncronos, o que significa que eles são contínuos e fornecem dados em uma taxa constante, como um áudio <acronym>PCM</acronym>. O qualificador async especifica um fluxo assíncrono, que é usado por fluxos de dados não contínuos. O exemplo mais comum de um fluxo assíncrono são mensagens &MIDI;. </para>
<para>A chave multi, somente válida para fluxos de entrada, indica que a interface suporta um número variável de entradas. Isto é útil para implementar dispositivos como mixadores que podem aceitar um grande número de fluxos de entrada. </para>
<para>Atributos são dados associados com uma instância de uma interface. Eles são declarados como variáveis membro em C++, e podem usar qualquer um dos tipos primitivos booleano, byte, longo, string ou flutuante. Você pode também usar estruturas definidas pelo usuários ou tipos de enumeração bem como sequências delimitadas de variáveis usando a sintaxe sequência<tipo>. Atributos podem opcionalmente ser marcados como somente leitura. </para>
<para>Como em C++, métodos podem ser definidos em interfaces. Os parâmetros do métodos são restritos aos mesmos tipos dos atributos. A chave oneway indica um método que retorna imediatamente e é executado de maneira assíncrona. </para>
<para>Diversas interfaces de módulos padrão já estão definidas para você no &arts;, como a <interfacename>StereoEffect</interfacename>, e <interfacename>SimpleSoundServer</interfacename>. </para>
<para>Um exemplo simples de um módulo obtido do &arts; é o módulo de retardo constante, encontrado no arquivo <filename>tdemultimedia/arts/modules/artsmodules.idl</filename>. A definição de interface é listada abaixo. </para>
<para>Este módulo é herdeiro do <interfacename>SynthModule</interfacename>. Esta interface, definida em <filename>artsflow.idl</filename>, define métodos padrão implementados em todos os módulos de sintetização de música. </para>
<para>O efeito CDELAY retarda um fluxo de áudio estéreo de um valor de tempo especificado como um parâmetro de ponto flutuante. A definição de interface possui um atributo do tipo flutuante para armazenar o valor de retardo. Isto define dois fluxos de entrada de áudio e dois fluxos de saída de áudio (tipicamente para efeitos estéreo). Nenhum método é necessário além dos que ele herda. </para>
<para>O primeiro caso é o mais simples: ao receber 200 amostras de entrada o módulo produz 200 amostras de saída. Ele somente produz saída quando ele recebe entrada. </para>
<para>O segundo caso produz número diferente de amostras de saída ao receber 200 amostras de entrada. Isto depende de que conversão é executada, mas o número é conhecido a seguir. </para>
<para>O terceiro caso é mais complicado. A partir dos dados recebidos você não pode adivinhar quanto dados os 200 bytes de entrada gerarão (provavelmente muito mais de 200 bytes, mas...). </para>
<para>No &arts;-0.3.4, somente fluxos do primeiro tipo serão manipulados, e a maioria das coisas funciona bem. Este é provavelmente o que você precisa mais ao escrever módulos que processam áudio. O problema com os outros, e mais complexos tipos de fluxo, é que eles são difíceis de programar, e que você não precisa destes recursos na maioria das vezes. É por isto que nós fazemos isto com dois tipos de fluxo diferentes: síncronos e assíncronos. </para>
<para>A função <function>calculateBlock()</function> será chamada quando dados suficientes estiverem disponíveis, e o módulo pode confiar nos ponteiros que apontam para os dados. </para>
<para>Módulos podem algumas vezes produzir dados, ou com taxa de amostragem variável, ou somente se eles tiverem entrada a partir de algum descritor arquivado. Eles não se limitam pela regra que <quote>deve ser capaz de satisfazer requisitos de qualquer tamanho</quote>. </para>
<para>Fluxos de saída: existem funções explícitas para alocar pacotes, enviar pacotes - e um mecanismo de eleição adicional que lhe dirá quando você deve criar mais algum dado. </para>
<para>Fluxos de entrada: você obtém uma chamada quando recebe um novo pacote - você deve dizer quando você está processando todos os dados deste pacote, o que não deve acontecer de uma vez (você pode informar isto mais tarde, e se todos foram processados um pacoto, se será liberado/reusado) </para>
<para>Ao você declarar fluxos, você usa a chave <quote>async</quote> para indicar que deseja criar um fluxo assíncrono. Assim, por exemplo, consideremos que você deseja converter um fluxo assíncrono de bytes para um fluxo síncrono de amostras. Sua interface pode parecer-se com isto: </para>
<para>Como enviar os dados? O primeiro método é chamado <quote>empurrar e entregar</quote>. Com fluxos assíncronos você envia dados como pacotes. Ou seja, você envia pacotes individuais com bytes como no exemplo acima. O processo atual é: alocar um pacote, preenchê-lo, enviá-lo. </para>
<para>Este é um exemplo bem simples, mas se você deseja enviar pacotes extamanete tão rápido quanto o recebedor possa processá-los, você precisa de outra abordagem, o método <quote>puxar e entregar</quote>. Você pede para enviar pacotes tão rápido quanto o recebedor esteja pronto para processá-lo. Você inicia com uma determinada quantidade de pacotes que enviou. Assim que o recebedor processar um pacote após o outro, você começa a recarregar com novos dados, e enviá-los novamente. </para>
<para>Isto significa que você deseja enviar pacotes pelos dados de saída. Você deseja iniciar enviando 8 pacotes de uma vez, e assim que o recebedor processar alguns deles, você deseja receber mais. </para>
<para>É isto. Quando você não tiver mais qualquer dado, você pode começar a enviar pacotes com tamanho zero, que interromperá o processo de puxar. </para>
<para>Nós apenas discutimos o envio de dados. O recebimento de dados é bem mais simples. Suponhamos que você tenha um filtro ToLower simples, que simplesmente converte todas as letras para minúsculas: </para>
<para>Como pode ver, para cada pacote de chegada você obtém uma chamada para uma função (a chamada <function>process_indata</function> em seu caso). Você precisa chamar o método <methodname>processed()</methodname> de um pacote para indicar que você já o processou. </para>
<para>Aqui está uma dica de implementação: se o processamento demorar muito 9&ie; se você deseja esperar pela saída da placa de som ou algo parecido). não chame o processo imediatamente, mas armazene todo pacote de dados e chame processed somente tão logo você realmente tenha processado o pacote. Deste modo, remetentes possuem a chance de saber quanto tempo ele realmente leva para fazer seu trabalho. </para>
<para>Como sincronização não é tão agradável com fluxos assíncronos, você deve usar fluxos síncronos sempre que possível, e fluxos assíncronos somente quando necessário. </para>
<para>Suponhamos que você tenha 2 objetos, por exemplo um AudioProducer e um AudioConsumer. O AudioProducer tem um fluxo de saída e o AudioConsumer tem um de entrada. Cada vez que você desejar conectá-los, você usará estes 2 fluxos. O primeiro uso dos padrões é para permitir que você crie conexões sem especificar as portas neste caso. </para>
<para>Agora suponhamos que os objetos acima possam manipular estéreo, e cada um tenha uma porta <quote>left</quote> e <quote>right</quote>. Você gostaria ainda de conectá-los tão facilmente quanto antes. Mas como pode o sistema de conexão saber que porta de saída conectar a qual porta de entrada? Não existe maneira de mapear corretamente os fluxos? Os padrões são então usados para especificar diversos fluxos, com uma ordem. Assim, quando você conectar um objeto com 2 fluxos de saída padrão a outro com 2 fluxos de entrada padrão, você não precisa especificar as portas, e o mapeamento será feito corretamente. </para>
<para>É claro, isto não se limita ao estéreo. Qualquer número de fluxos pode ser estabelecido como padrão se necessário, e a função de conexão verificará se o número de padrões de 2 objetos correspondem (na direção necessária) se você não especificar as portas a usar. </para>
<para>Neste exemplo, o objeto irá esperar que duas portas de entrada sejam conectadas por padrão. A ordem é a especificada na linha default, assim um objeto como este: </para>
<para>Criará conexões a partir de <quote>couic</quote> para <quote>input1</quote>, e <quote>bzzt</quote> para <quote>input2</quote> automaticamente. Observe que uma vez que existe somente uma saída para o mixador, ela será tornada padrão neste caso (veja abaixo). A sintaxe usada no gerador de ruído é útil para declarar uma ordem diferente da estabelecida na declaração, ou selecionar somente algumas portas como padrão. A direção das portas nesta linha serão descobertas pelo &mcopidl; assim não as especifique. Você pode misturar portas de entrada e saída na mesma linha, somente a ordem é importante. </para>
<para>Se uma lista padrão é especificada no &IDL;, então a usa. Portas pai podem ser colocadas na lista também, sejam elas padrão no pai ou não. </para>
<para>Caso contrário, herda os padrões do pai. A ordem é parente1 padrão1, parente1 padrão2 ..., parente2 padrão 1... Se existir um ancestral comum usando 2 ramos pai, um lista <quote>pública virtual</quote> mesclada é feita na qual o padrão é a primeira ocorrência da lista. </para>
<para>Notificações de mudança de atributos são uma maneira de saber quando um atributo muda. Elas são um pouco semelhantes aos sinais e slots do &Qt; ou Gtk. Por exemplo, se você tiver um elemento &GUI;, um índice deslizante, que configura um número entre 0 e 100, você normalmente terá um objeto que faz algo com este número (por exemplo, ele pode estar controlando o volume de algum sinal de áudio). Assim você desejaria que sempre que o índice fosse movido, o objeto que escalona o volume fosse notificado. Uma conexão entre o remetente e o destinatário. </para>
<para>O &MCOP; lida com isto sendo capaz de fornecer notificações quando atributos mudam. O que quer que seja declarado como <quote>atributo</quote> no &IDL; pode emitir estas notificações, e deve fazer isso, sempre que for modificado. O que quer que seja declarado como <quote>atributo</quote> também pode receber estas notificações de mudaça. Assim, por exemplo, se você possui duas interfaces &IDL;, como estas: </para>
<para>Você pode conectá-las usando notificações de mudanças. Isto funciona usando a operação de conexão do sistema de fluxo normal. Neste caso, o código C++ para conectar dois objetos se parecerá com isto: </para>
<para>Como pode ver, cada atributo oferece dois fluxos diferentes, um para enviar as notificações de mudança, chamado <function><replaceable>nomeatributo</replaceable>_changed</function>, e um para receber notificações de mudança, chamado <function>nomeatributo</function>. </para>
<para>É importante saber que as notificações de mudança e fluxos assíncronos são compatíveis. Eles também são transparentes à rede. Assim você pode conectar uma notificação de mudança de um atributo flutuante de um widget que a &GUI; possua com um fluxo assíncrono de um módulo sintetizador sendo executado em outro computador. Isto, é claro, implica que as notificações de mudança <emphasis>não são síncronas</emphasis>, ou seja, após você ter enviado a notificação de mudança, ela pode levar algum tempo até ela ser efetivamente recebida. </para>
<para>Ao implementar objetos que possuam atributos, você precisa enviar notificações de mudança sempre que um atributo muda. O código para fazer isto se parece com isto: </para>
<para>É altamente recomendável usar um código como este para todos os objetos que você implementar, assim estas notificações de mudança podem ser usadas por outras pessoas. Você deve também no entanto esvaziar as notificação enviadas frequentemente, assim se você estiver realizando um processamento de sinal, é provavelmente melhor você manter um monitoramento ao enviar sua última notificação, de modo que você não envie uma com cada amostra que você processar. </para>
<para>Será especialmente útil o uso de notificações de mudança juntamente com escopos (coisas que visualizam dados de áudio por exemplo), elementos gui, widgets de controle, e monitoramento. Código usando isto existe em <filename class="directory">tdelibs/arts/tests</filename>, e na implementação experimental da artsgui, que você pode encontrar em <filename class="directory">tdemultimedia/arts/gui</filename>. </para>
<para>O arquivo <literal role="extension">.mcoprc</literal> (em cada pasta pessoal do usuário) pode ser usado para configurar o &MCOP; de diversas maneiras. Atualmente, os parâmetros possíveis são os seguintes: </para>
<para>O nome de uma interface a ser usada para comunicação global. A comunicação global é usada para encontrar outros objetos e obter o cookie secreto. Múltiplos clientes/servidores &MCOP; que devem ser capazes de conversar um com os outros precisam ter um objeto GlobalComm que é capaz de compartilhar informações entre eles. Atualmente, os valores possíveis são <quote>Arts:TmpGlobalComm</quote> para comunicar através da pasta <filename class="directory">/tmp/mcop-<replaceable>nomeusuário</replaceable></filename> (que somente funcionará em um computador local) e <quote>Arts::X11GlobalComm</quote> para comunicar através das propriedades da janela raiz no servidor X11. </para>
<para>Especifica quais extensões de pasta (na forma de bibliotecas compartilhadas) são carregadas. Valores múltiplos podem ser especificados separados por vírgula. </para>
<title>&MCOP; para Usuários do <acronym>CORBA</acronym></title>
<para>Se você já usou o <acronym>CORBA</acronym> antes, você verá que o &MCOP; é quase a mesma coisa. De fato, o &arts; antes da versão 0.4 usava o <acronym>CORBA</acronym>. </para>
<para>A idéia básica do <acronym>CORBA</acronym> é a mesma: você implementa objetos (componentes). Usando os recursos do &MCOP;, seus objetos não estão somente disponíveis como classes normais a partir do mesmo processo (através das técnicas padrão do C++) - eles também estão disponíveis para servidores remotos de maneira transparente. Para isto funcionar, a primeira coisa que você precisa fazer é especificar a interface de seus objetos em um arquivo &IDL; - da mesma maneira que o &IDL; do <acronym>CORBA</acronym>. Existem somente algumas poucas diferenças. </para>
<title>Recursos do <acronym>CORBA</acronym> Que Estão Faltando No &MCOP;</title>
<para>No &MCOP; não existe parâmetros <quote>in</quote> e <quote>out</quote> nas invocações de método. Parâmetros são sempre de entrada, o código de retorno é sempre de saída, o que significa que a interface: </para>
<title>Recursos do <acronym>CORBA</acronym> Que São Diferentes No &MCOP;</title>
<para>Você declara sequências como <quote><replaceable>tipo</replaceable>sequence</quote> no &MCOP;. Não existe necessidade de um typedef. Por exemplo, ao invés de: </para>
<para>Você pode declarar fluxos, que então serão avalidados pelo ambiente de trabalho do &arts;. Fluxos são declarados de maneira semelhante aos atributos. Por exemplo: </para>
<para>Isto diz que seu objeto aceitará dois fluxos de entrada síncrona de áudio chamados signal1 e signal2. Síncrona significa que estes fluxos enviarão x amostras por segunto (ou outro tempo), assim o agendador sempre garantirá que seja fornecido uma quantidade balanceada de dados de entrada (⪚ 200 amostras de signal1 existirão e 200 amostras de signal2 existirão). Você garantirá que se seu objeto for chamado com estas 200 amostras de signal1 + signal2, ele será capaz de produzir exatamente 200 amostras para o outvalue. </para>
<para>Strings usam a classe <classname>sting</classname> do <acronym>STL</acronym> do C++. Quando armazenado em sequências, eles são armazenados como <quote>plano</quote>, o que significa que eles são considerados um tipo primitivo. Assim, eles precisam de cópia. </para>
<para>As estruturas são todas derivadas da classe <classname>Type</classname> do &MCOP;, e são geradas no compilador de &IDL; do &MCOP;. Quando forem armazenadas em sequências, elas não serão armazenadas <quote>planas</quote> , mas sim como referências porque, caso contrário, iriam ocorrer várias cópias. </para>
<para>Após passar as interfaces pelo compilador de &IDL;, você precisa de derivar da classe <classname>_skel</classname>. Por exemplo, considere que definiu a sua interface da seguinte forma: </para>
<para>Você pode passar isso pelo compilador de &IDL;, invocando o comando <userinput><command>mcopidl</command> <parameter>ola.idl</parameter></userinput>, o que por sua vez irá gerar o <filename>ola.cc</filename> e o <filename>ola.h</filename>. Para o implementar, você precisa de definir uma classe C++ que herde do esqueleto: </para>
<programlisting>// Arquivo de inclusão de C++ - inclua o ola.h em algum lugar
<para>Logo que faça isso, você terá um objeto que poderá comunicar-se usando o &MCOP;. Basta criar um (usando as funcionalidades normais do C++ para criar um objeto): </para>
<para>Uma vez que os servidores de &MCOP; irão atender os pedidos numa porta <acronym>TCP</acronym>, potencialmente todos (se você estiver na Internet) poderão tentar ligar-se aos serviços do &MCOP;. Por isso, é importante autenticar os clientes. O &MCOP; usa o protocolo md5-auth. </para>
<para>Toda vez que um cliente se conecta, ele verifica se o cliente conhece esse cookie secreto, sem o transferir de fato (de modo que nem quem esteja escutando o tráfego de rede possa descobrir). </para>
<para>Para fornecer a cada cliente esse cookie secreto, o &MCOP; irá (normalmente) colocá-lo na pasta <filename class="directory">mcop</filename> (em <filename class="directory">/tmp/mcop-<envar>USER</envar>/secret-cookie</filename>). Claro, você poderá copiá-lo para outros computadores. Contudo, se o fizer, use um mecanismo de transferência seguro, como o <command>scp</command> (do <application>ssh</application>). </para>
<para>A autenticação dos clientes usa os seguintes passos: </para>
<para>[SERVIDOR] verifica que, ao embaralhar o R e o S obterá o mesmo resultado que o cookie M recebido do cliente. Em caso afirmativo, a autenticação foi bem-sucedida. </para>
<para>O algoritmo de dispersão do MD5 não permite descobrir o <quote>texto original</quote>, que é o cookie secreto S e o cookie aleatório R (o qual é conhecido, de qualquer forma), a partir do cookie embaralhado M. </para>
<para>Antes de a autenticação ser bem sucedida, o servidor não irá receber outras mensagens da conexão. Em vez disso, se o servidor por exemplo estiver esperando uma mensagem <quote>ClientHello</quote> e obtiver uma mensagem de mcopInvocation, irá interromper a conexão. </para>
<para>Se o cliente não enviar uma mensagem de &MCOP; totalmente válida (sem o código especial do &MCOP; no cabeçalho da mensagem) na fase de autenticação, mas sim outra coisa qualquer, a conexão será interrompida. </para>
<para>Se o cliente tentar enviar uma mensagem muito grande (> 4096 bytes na fase de autenticação, o tamanho da mensagem é truncado para 0 bytes, o que fará com que não seja aceita para a autenticação). Isto é para evitar que os clientes não-autenticados enviem mensagens de ⪚ 100 megabytes, o que faria com que fosse recebida e com que o servidor estourasse com falta de memória. </para>
<para>Existem semelhanças conceituais com o <acronym>CORBA</acronym>, mas pretende expandí-las de todas as formas necessárias para as operações multimídia em tempo-real. </para>
<para>Oferece um modelo de objetos multimídia, o qual poderá ser usado para: a comunicação entre os componentes num espaço de endereçamento (um processo) e entre componentes que existam em tarefas, processos ou mesmo máquinas diferentes. </para>
<para>Tudo junto, será desenhado para uma performance extremamente alta (de modo que tudo seja otimizado para ser extremamente rápido), o que é adequado para as aplicações multimídia bastante comunicativas. Por exemplo, a transmissão de vídeos é uma das aplicações do &MCOP;, onde a maioria das implementações de <acronym>CORBA</acronym> 'cairiam de joelhos'. </para>
<para>Se você souber que vai receber uma cadeia de caracteres, não precisa ler até encontrar o byte zero para descobrir o seu tamanho, contudo, </para>
<para>Se você souber que vai receber uma sequência de cadeias de caracteres, você precisa saber o tamanho de cada uma delas para descobrir o fim da sequência, uma vez que as cadeias de caracteres possuem tamanho variável. Mas se você usar as cadeias de caracteres para algo útil, você terá de fazer isso de qualquer jeito, por isso não se perde nada. </para>
<entry>é codificado como quatro bytes, em que o byte mais significativo vem primeiro, de modo a que o número 10001025 (correspondente à 0x989a81) será codificado como:</entry>
<entry><para>é codificado como um <type>long</type>, contendo o tamanho da cadeia de caracteres seguinte, e pela sequência de caracteres propriamente dita, terminando com um byte zero (que está incluído na contagem do tamanho).</para>
<entry><para>é codificado como um byte, contendo 0 se for <returnvalue>false</returnvalue> (falso) ou 1 se for <returnvalue>true</returnvalue> (verdadeiro), de modo a que o valor booleano <returnvalue>true</returnvalue> é codificado como:</para></entry>
<entry><para>é codificado na representação de 4 bytes do IEEE754 - a documentação detalhada de como o IEEE funciona estão aqui: <ulink url="http://twister.ou.edu/workshop.docs/common-tools/numerical_comp_guide/ncg_math.doc.html">http://twister.ou.edu/workshop.docs/common-tools/numerical_comp_guide/ncg_math.doc.html</ulink> e aqui: <ulink url="http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html">http://java.sun.com/docs/books/vmspec/2nd-edition/html/Overview.doc.html</ulink>. Deste modo, o valor 2,15 seria codificado como:</para></entry>
<para>Se você precisar de fazer referência a um tipo, todos os tipos primitivos são referidos pelos nomes indicados acima. As estruturas e as enumerações possuem nomes próprios (como Header). As sequências são referidas como um *<replaceable>tipo normal</replaceable>, de modo que uma sequência de longs é um <quote>*long</quote> e uma sequência de estruturas Header é um <quote>*Header</quote>. </para>
<para>Depois de receber o cabeçalho, o tratamento do protocolo (conexão) poderá receber a mensagem por completo, sem olhar para o seu conteúdo. </para>
<para>O messageLength no cabeçalho é, obviamente em alguns casos, redundante, o que significa que esta aproximação não é minimalista no que respeita ao número de bytes. </para>
<para>Contudo, isto conduz a uma implementação simples (e rápida) do processamento não em bloqueante de mensagens. Com a ajuda do cabeçalho, as mensagens poderão ser recebidas pelas classes de tratamento do protocolo em segundo plano (não-bloqueante), se existirem demasiadas ligações ao servidor, todas elas poderão ser servidas em paralelo. Você não precisa de olhar para o conteúdo da mensagem para recebê-la (e para determinar que terminou), basta olhar para o cabeçalho, assim o código para isso é relativamente simples. </para>
<para>Logo que uma mensagem esteja lá, ela poderá ser descodificada e processada em um único passo, sem se preocupar com os casos em que nem todos os dados foram recebidos (porque o messageLength garante que tudo está lá). </para>
<para>Para invocar um método remoto, você precisa enviar a seguinte estrutura no corpo de uma mensagem de &MCOP; com o messageType = 1 (mcopInvocation): </para>
<para>depois disso, você envia os parâmetros como uma estrutura, ⪚ se você invocar o método concatenar(string s1, string s2), você envia uma estrutura do tipo </para>
<para>se o método foi declarado como só de ida0 - o que significa que é assíncrono sem código devolvido - então isto é tudo. Caso contrário, você iria receber como resposta uma mensagem com o messageType = 2 (mcopReturn) </para>
<para>em que o <tipo-resultante> é o tipo do resultado. Como os tipos void são omitidos na codificação, você também poderá só escrever o requestID se regressar de um método void. </para>
<para>Para fazer as invocações, você teria de conhecer os métodos que um objeto suporta. Para fazer isto, o methodID 0, 1, 2 e 3 estão pré-destinados a certas funcionalidades. Isto é </para>
<para>o campo parameters contém os componentes do tipo que indicam os tipos dos parâmetros. O tipo do valor devolvido é indicado no campo type do MethodDef. </para>
<para>Na forma restrita, só os métodos <methodname>_lookupMethod()</methodname> e <methodname>_interfaceName()</methodname> são diferentes de objeto para objeto, enquanto que o <methodname>_queryInterface()</methodname> e o <methodname>_queryType()</methodname> são sempre os mesmos. </para>
<para>O que são esses methodIDs? Se você fizer uma invocação de &MCOP;, irá ficar esperando para passar um número para o método que você está invocando. A razão para isso é que os números podem ser processados muito mais depressa do que as cadeias de caracteres ao executar um pedido ao &MCOP;. </para>
<para>Por isso, como é que obtém esses números? Se você souber a assinatura do método, existe um MethodDef que descreve o método (e que contém o nome, o tipo, os nomes e os tipos de parâmetros, entre outras coisas) e você poderá passar isso ao _lookupMethod do objeto onde deseja invocar um método. Dado que o _lookupMethod está pré-associado ao methodID 0, você não deverá ter problemas ao fazê-lo. </para>
<para>Por outro lado, se você não souber a assinatura do método, você poderá descobrir os métodos que são suportados, usando o _interfaceName, o _queryInterface e o _queryType. </para>
<para>Uma vez que o &kde; abandonou o <acronym>CORBA</acronym> por completo e está usando o &DCOP; em todo o sistema, naturalmente a questão a se levantar é porque o &arts; não faz isso também. Afinal de contas, o suporte do &DCOP; está no <classname>TDEApplication</classname>, é bem-mantido, supostamente integra-se bem com a libICE, entre outras coisas. </para>
<para>Uma vez que existirá (potencialmente) uma grande quantidade de pessoas a se perguntar se ter o &MCOP; além do &DCOP; é realmente necessário, aqui está a resposta. Não me levem a mal, porque eu não está dizendo que o <quote>o &DCOP; é ruim</quote>. Eu estou simplesmente tentando dizer que <quote>o &DCOP; não é a solução adequada para o &arts;</quote> (embora seja uma boa solução para outras coisas). </para>
<para>Primeiro, você precisa de compreender para que o &DCOP; foi criado. Desenvolvido em dois dias durante o encontro &kde;-TWO, pretendia ser o mais simples possível, um protocolo de comunicações realmente <quote>leve</quote>. Especialmente, a implementação descartou tudo que pudesse envolver complexidade, como por exemplo um conceito completo de como os tipos de dados seriam codificados. </para>
<para>Ainda que o &DCOP; não se preocupe com certas coisas (por exemplo: como é que se envia uma cadeia de caracteres de forma transparente na rede?) - isso precisa de ser feito. Por isso, tudo o que o &DCOP; não faz, fica a cargo do &Qt; nos aplicativos do &kde; que usam o &DCOP; hoje em dia. Isto é em grande parte gestão de tipos (usando o operador de serialização do &Qt;). </para>
<para>Por isso, o &DCOP; é um protocolo mínimo que permite perfeitamente aos aplicativos do &kde; enviarem mensagens simples do tipo <quote>abrir uma janela a apontar para http://www.kde.org</quote> ou <quote>os seus dados de configuração mudaram</quote>. Contudo, dentro do &arts; o foco situa-se em outras coisas. </para>
<para>A idéia é que alguns pequenos plugins do &arts; irão comunicar-se, trocando algumas estruturas de dados como <quote>eventos MIDI</quote> e <quote>ponteiros de posição na música</quote> ou <quote>gráficos de fluxo</quote>. </para>
<para>Estes são tipos de dados complexos, os quais deverão ser enviados entre objetos diferentes e passados como sequências ou parâmetros. O &MCOP; fornece um conceito de tipos para definir dados complexos a partir de dados mais simples (de forma semelhante às estruturas ou vetores no C++). O &DCOP; não se preocupa com os tipos como um todo, por isso este problema seria deixado para o programador - como: criar classes de C++ para os tipos, certificando-se que eles pudessem serializar-se corretamente (por exemplo: suportar o operador de transmissão do &Qt;). </para>
<para>Mas desta forma, eles seriam inacessíveis a tudo o que não fosse codificação direta de C++. Especificamente, você não poderia desenhar uma linguagem de scripting que conhecesse todos os plugins de tipo a que poderão estar expostos, uma vez que eles não se descrevem a si próprios. </para>
<para>O mesmo argumento se aplica também às interfaces. Os objetos do &DCOP; não expõem as suas relações, hierarquias de herança, etc. - se você fosse criar um navegador de objetos que lhe mostrasse <quote>que atributos tem este objeto</quote>, seria mal-sucedido. </para>
<para>Embora o Matthias tenha dito que existe uma função especial <quote>functions</quote> em cada objeto que lhe indica os métodos que um dado objeto suporta, isto deixa de fora coisas como os atributos (propriedades), as sequências e as relações de herança. </para>
<para>Isto quebra seriamente os aplicativos como o &arts-builder;. Mas lembre-se. o &DCOP; não pretendia ser um modelo de objetos (uma vez que o &Qt; já tem um com o <application>moc</application> e semelhantes), nem pretende ser algo semelhante ao <acronym>CORBA</acronym>, mas simplesmente uma forma de fornecer comunicação entre aplicativos. </para>
<para>Porque o &MCOP; ainda existe é: deverá funcionar perfeitamente com canais entre objetos. O &arts; faz um uso intensivo de pequenos plugins, que se interligam entre si com os fluxos. A versão em <acronym>CORBA</acronym> do &arts; tinha de introduzir uma divisão muito incômoda entre <quote>os objetos SynthModule</quote>, os quais eram os módulos de trabalho internos que faziam a transmissão e <quote>a interface <acronym>CORBA</acronym></quote>, que era algo externo. </para>
<para>Muito do código preocupava-se em fazer a interação entre <quote>os objetos SynthModule</quote> e <quote>a interface <acronym>CORBA</acronym></quote> parecer natural, mas não o era, porque o <acronym>CORBA</acronym> não sabia nada sobre fluxos. O &MCOP; sabe. Olhe para o código (algo como o <filename>simplesoundserver_impl.cc</filename>). Muito melhor! Fluxos podem ser declarados na interface dos módulos e implementados de forma natural. </para>
<para>Ninguém pode negar. Uma das razões pela qual o &MCOP; foi feito foi a velocidade. Aqui estão alguns argumentos de porque o &MCOP; será definitivamnete mais rápido que o &DCOP; (sem sequer mostrar imagens). </para>
<para>Uma invocação do &MCOP; terá um cabeçalho com seis <quote>long</quote>s. Isto é: </para>
<para>Depois disso, seguem-se os parâmetros. Repare que a decodificação destes é extremamente rápida. Você poderá usar pesquisas em tabelas para encontrar o objeto e a função de decodificação do método, o que significa que a complexidade é O(1) (levará a mesma quantidade de tempo, independentemente de quantos objetos estão ativos, ou de quantas funções existem). </para>
<para>No &DCOP;, todos os pedidos são passados através de um servidor (o <application>DCOPServer</application>). Isto significa que o processo de uma invocação síncrona se assemelha a: </para>
<para>O <application>DCOPserver</application> (o intermediário) recebe a invocação e procura onde precisa ir, enviando para o servidor <quote>real</quote>. </para>
<para>Digamos que ambos foram implementados corretamente, a estratégia ponto-a-ponto do &MCOP; deverá ser mais rápida por um fator de 2, do que a estratégia de intermediário do &DCOP;. Repare contudo que existiam razões para escolher a estratégia do &DCOP;, principalmente: se você tiver 20 aplicativos rodando, se cada um estiver conversando com outro, você precisa de 20 conexões no &DCOP;, e de 200 com o &MCOP;. Contudo, no caso de multimídia, isto supostamente não será a configuração normal. </para>
<para>Tentou-se comparar o &MCOP; com o &DCOP;, fazendo uma invocação do tipo adicionar dois números. Alterou-se o testdcop para conseguir isto. Porém, o teste pode não ter sido confiável do lado do &DCOP;. Invocou-se o método no mesmo processo que fez a chamada para o &DCOP;, e não se soube como se ver livre de uma mensagem de depuração, pelo que foi feita redireção do resultado. </para>
<para>O teste só usava um objeto e uma função, esperando que os resultados do &DCOP; começassem a descer com mais objetos e funções, enquanto os resultados do &MCOP; deveriam se manter iguais. Também, o processo do <application>dcopserver</application> não estava conectado a nenhum dos outros aplicativos, uma vez que, se existissem outros aplicativos conectados, a performance do encaminhamento iria decrescer. </para>
<para>O resultado obtido foi que, enquanto o &DCOP; obteve cerca de 2000 invocações por segundo, o &MCOP; obteve um pouco mais de 8000 invocações por segundo. Isto resulta em um fator de 4. Sabe-se que o &MCOP; não está ajustado para o máximo possível, ainda. (Comparação: o <acronym>CORBA</acronym>, implementado no mico, faz algo entre 1000 e 1500 invocações por segundo). </para>
<para>Se você quiser dados <quote>brutos</quote>, pense em fazer algum aplicativo de medida de performance para o &DCOP; e envie-o para mim. </para>
<para>O <acronym>CORBA</acronym> tinha uma funcionalidade interessante na qual você poderia usar os objetos que implementou uma vez, como <quote>processos de servidor separados</quote> ou como <quote>bibliotecas</quote>. Você poderia usar o mesmo código para tal, e o <acronym>CORBA</acronym> iria decidir transparentemente o que fazer. Com o &DCOP;, isto não é realmente pretendido, e tanto quanto se sabe não é possível realmente. </para>
<para>O &MCOP;, por outro lado, deverá suportá-lo desde o início. Por isso, você poderá rodar um efeito dentro do &artsd;. Mas se você for um editor de ondas, você poderá optar por rodar o mesmo efeito dentro do espaço do processo. </para>
<para>Embora o &DCOP; seja, em grande medida, uma forma de comunicação entre aplicativos, o &MCOP; também o é. Especialmente para a transmissão multimídia, o que é importante (uma vez que você poderá rodar vários objetos &MCOP; em paralelo, para resolver uma tarefa de multimídia no seu aplicativo). </para>
<para>Ainda que o o &MCOP; não o faça de momento, as possibilidades estão em aberto para implementar as funcionalidades de qualidade de serviço. Algo do gênero <quote>aquele evento &MIDI; é mesmo MUITO importante, em comparação com esta invocação</quote>. Ou algo do tipo <quote>necessita de estar ali a tempo</quote>. </para>
<para>Por outro lado, a transferência de fluxos poderá ser integrada no protocolo &MCOP; sem problemas e ser combinada com elementos de <acronym>QoS</acronym>. Uma vez que o protocolo poderá ser alterado, a transferência de fluxos do &MCOP; não deverá ser mais lenta do que uma transmissão convencional de <acronym>TCP</acronym>, mas: é mais fácil e mais consistente de usar. </para>
<para>Não existe necessidade de basear uma plataforma de multimídia no &Qt;. Ao decidir isso, e usando toda aquela serialização e outras funcionalidades de fluxo do &Qt;, iria conduzir facilmente a que a plataforma se tornasse apenas para o &Qt; (ou apenas para o &kde;). Quer dizer: tão logo se veja os GNOMEs começando a usar o &DCOP;, também, ou algo do gênero, provavelmente eu estarei errado. </para>
<para>Enquanto se sabe que o &DCOP; basicamente não sabe nada sobre os tipos de dados que envia, de modo que você poderia usar o &DCOP; sem usar o &Qt;, veja como é usado no uso do dia-a-dia do &kde;: as pessoas enviam tipos como o <classname>QString</classname>, o <classname>QRect</classname>, o <classname>QPixmap</classname>, o <classname>QCString</classname>, ..., de um lado para o outro. Estes usam a serialização do &Qt;. Por isso, se alguém optar por suportar o &DCOP; em um programa do GNOME, ele teria de afirmar que usava os tipos <classname>QString</classname>,... (ainda que não o faça, de fato) e emular a forma como o &Qt; faz a transmissão, ou então teria de enviar outros tipos de cadeias de caracteres, imagens e retângulos, o que deixaria de ser interoperável. </para>
<para>Bem, seja o que for, o &arts; pretendeu sempre funcionar com ou sem o &kde;, com ou sem o &Qt;, com ou sem o X11, e talvez com ou sem o &Linux; (e não há problema nenhum com as pessoas que o transpõem para um sistema operacional proprietário conhecido). </para>
<para>É a minha posição que os componentes não&GUI; deverão ser criados de forma independente da &GUI;, para possibilitar o compartilhamento destes pela maior quantidade de programadores (e usuários) possível. </para>
<para>É óbvio que o uso de dois protocolos de <acronym>IPC</acronym> pode causar inconveniências. Ainda mais, se ambos não forem normatizados. Contudo, pelas razões indicadas acima, a mudança para o &DCOP; não é uma opção. Se existir um interesse significativo em encontrar uma forma de unir os dois, ok, poderemos tentar. Até poderemos tentar fazer com que o &MCOP; fale <acronym>IIOP</acronym>, onde então poderemos passar a ter um <acronym>ORB</acronym> de <acronym>CORBA</acronym>. </para>
<para>Eu falei com o Matthias Ettrich um pouco sobre o futuro dos dois protocolos e encontramos diversas formas de como as coisas poderão seguir daqui para a frente. Por exemplo, o &MCOP; poderia tratar da comunicação de mensagens no &DCOP;, colocando os protocolos um pouco mais juntos. </para>
<para>Assim algumas soluções possíveis seriam: </para>
<para>Criar uma gateway de &MCOP; - &DCOP; (o qual deverá ser possível, e possibilitaria a interoperabilidade) - nota: existe um protótipo experimental, se você quiser ver algo sobre o assunto. </para>
<para>Integrar tudo o que os usuários do &DCOP; esperam no &MCOP;, e tentar apenas usar o &MCOP; - uma pessoa até poderia adicionar uma opção de <quote>intermediário</quote> no &MCOP;, também ;) </para>
<para>Contudo, poderá não ser a pior possibilidade para usar cada protocolo em tudo em que se pensou usar (existem algumas grandes diferenças nos objetivos de desenho), e não vale a pena tentar juntá-los num só. </para>