Introdução
Instalação
Guias
- Engine
- Profile
- Browser
- BrowserView
- Navegação
- Conteúdo
- DOM
- JavaScript
- Pop-ups
- Diálogos
- Downloads
- Extensões
- Rede
- Cache
- Cookies
- Proxy
- Autenticação
- Plugins
- Impressão
- Senhas
- Perfis de dados do Usuário
- Cartões de Crédito
- Mídia
- Área de transferência
- Zoom
- Corretor Ortográfico
- Implantação
- Chromium
Resolução de Problemas
Mídia
Este guia apresenta uma visão geral dos formatos de vídeo e áudio suportados, descreve como controlar o áudio, obtém informações sobre webcams e microfones disponíveis, etc.
Codecs
Google Chrome e Chromium diferem de várias formas, incluindo os conjuntos de codecs de áudio e vídeo que suportam.
A tabela abaixo mostra quais os codecs suportados pela base de código dos navegadores correspondentes.
Chromium | Google Chrome | |
---|---|---|
AAC | sim | |
AV1 | sim | sim |
FLAC | sim | sim |
H.264 | sim | |
HEVC | sim | |
MP3 | sim | sim |
Opus | sim | sim |
Theora | sim | sim |
Vorbis | sim | sim |
VP8 | sim | sim |
VP9 | sim | sim |
WAV | sim | sim |
Como você pode ver, o Google Chrome suporta determinados codecs que o Chromium não suporta. O motivo é que estes codecs são proprietários e não podem ser utilizados num projeto de código aberto ou comercial sem a obtenção de licenças dos titulares das patentes correspondentes.
Os diferentes codecs têm diferentes detentores de patentes. Por exemplo, para utilizar o H.264, as empresas têm de adquirir a licença da empresa Via LA. Você pode ler mais sobre os termos da licença no site Web.
Codecs Proprietários
Os detentores de patentes não licenciam codecs para o software que representa apenas uma parte do produto final implementado para os usuários finais, por exemplo, bibliotecas como o JxBrowser.
Para suportar codecs proprietários nos seus produtos, é necessário adquirir as licenças adequadas e ativar as seguintes funcionalidades proprietárias:
Engine engine = Engine.newInstance(
EngineOptions.newBuilder(renderingMode)
.enableProprietaryFeature(ProprietaryFeature.AAC)
.enableProprietaryFeature(ProprietaryFeature.H_264)
.enableProprietaryFeature(ProprietaryFeature.HEVC)
.build());
val engine = Engine.newInstance(
EngineOptions.newBuilder(renderingMode)
.enableProprietaryFeature(ProprietaryFeature.AAC)
.enableProprietaryFeature(ProprietaryFeature.H_264)
.enableProprietaryFeature(ProprietaryFeature.HEVC)
.build())
Com a licença e as funcionalidades proprietárias ativadas, será possível carregar páginas Web com os formatos AAC, HEVC e H.264 e reproduzir arquivos de áudio e vídeo, tal como no Google Chrome. Por padrão, os codecs proprietários estão desativados.
Importante: Os codecs H.264, HEVC e AAC são os componentes proprietários. Ao ativar estes codecs, você declara ter conhecimento de que H.264, HEVC e AAC são componentes proprietários e que você deve ter uma licença para utilizá-los. Para mais informações, você pode contatar os detentores de patentes: Via LA Licensing. A TeamDev não será responsável pela sua utilização dos codecs H.264, HEVC e AAC.
Video
O JxBrowser suporta totalmente o elemento <video>
HTML5 e pode reproduzir vídeo nos formatos suportados.
Se a biblioteca não conseguir reproduzir um vídeo ou se um formato de vídeo não for suportado, o JxBrowser sugere o download do arquivo de vídeo. Consulte Downloads para obter orientações sobre o gerenciamento de downloads.
Audio
Controle de Áudio
Utilizando Audio
é possível saber se o áudio está sendo reproduzido na página web carregada:
boolean audioPlaying = audio.isPlaying();
val audioPlaying = audio.isPlaying()
Se necessário, você pode ativar ou desativar o áudio na página Web carregada:
audio.mute();
audio.unmute();
audio.mute()
audio.unmute()
Para verificar se o áudio está silenciado, utilize o seguinte código:
boolean audioMuted = audio.isMuted();
val audioMuted = audio.isMuted()
Eventos de Áudio
Para saber se o áudio começou/parou de ser reproduzido na página Web carregada, pode subscrever os seguintes eventos:
browser.on(AudioStartedPlaying.class, event -> {});
browser.on(AudioStoppedPlaying.class, event -> {});
browser.on(AudioStartedPlaying::class.java) { event -> }
browser.on(AudioStartedPlaying::class.java) { event -> }
DRM
Widevine
Os serviços Web como Netflix ou Amazon Prime utilizam Widevine para distribuir os seus conteúdos codificados com DRM. Widevine é um componente propriedade da Google que é desativado por padrão. Para o ativar e reproduzir o conteúdo codificado por DRM, utilize a seguinte abordagem:
Engine engine = Engine.newInstance(
EngineOptions.newBuilder(renderingMode)
.enableProprietaryFeature(ProprietaryFeature.WIDEVINE)
.build());
val engine = Engine.newInstance(
EngineOptions.newBuilder(renderingMode)
.enableProprietaryFeature(ProprietaryFeature.WIDEVINE)
.build())
A versão do Chromium utilizada pela biblioteca suporta o Widevine apenas nas plataformas Windows e macOS. Não é suportado no Linux. Assim que o Chromium ativar o suporte do Widevine no Linux, também o ativaremos no JxBrowser.
Importante: Widevine é um componente proprietário da Google, regido pelos seus próprios termos de utilização. Para mais informações, consultar https://www.widevine.com/.
Câmera e Microfone
O JxBrowser suporta webcam e microfone.
Pode obter informações sobre todos os dispositivos de fluxo multimídia disponíveis utilizando o seguinte código:
MediaDevices mediaDevices = engine.mediaDevices();
// Obter todos os dispositivos de vídeo disponíveis, por exemplo, webcams.
List<MediaDevice> videoDevices = mediaDevices.list(MediaDeviceType.VIDEO_DEVICE);
// Obter todos os dispositivos de áudio disponíveis, por exemplo, microfones.
List<MediaDevice> audioDevices = mediaDevices.list(MediaDeviceType.AUDIO_DEVICE);
val mediaDevices = engine.mediaDevices()
// Obter todos os dispositivos de vídeo disponíveis, por exemplo, webcams.
val videoDevices = mediaDevices.list(MediaDeviceType.VIDEO_DEVICE)
// Obter todos os dispositivos de áudio disponíveis, por exemplo, microfones.
val audioDevices = mediaDevices.list(MediaDeviceType.AUDIO_DEVICE)
É possível detectar quando uma captura de mídia começa ou para de utilizar estes eventos:
browser.on(MediaStreamCaptureStarted.class, e -> {
System.out.println("Started capturing " + e.mediaStreamType());
});
browser.on(MediaStreamCaptureStopped.class, e -> {
System.out.println("Stopped capturing " + e.mediaStreamType());
});
browser.on(MediaStreamCaptureStarted::class.java) { e ->
println("Started capturing " + e.mediaStreamType())
}
browser.on(MediaStreamCaptureStopped::class.java) { e ->
println("Stopped capturing " + e.mediaStreamType())
}
Seleção do Dispositivo Multimídia
Quando uma página Web deseja utilizar uma webcam ou um microfone, você pode utilizar SelectMediaDeviceCallback
para indicar à página Web
qual dispositivo utilizar.
O exemplo seguinte demonstra como selecionar o primeiro dispositivo da lista de dispositivos disponíveis:
mediaDevices.set(SelectMediaDeviceCallback.class, params ->
Response.select(params.mediaDevices().get(0)));
mediaDevices.set(SelectMediaDeviceCallback::class.java,
SelectMediaDeviceCallback { params ->
Response.select(params.mediaDevices().first())
}
)
A chamada de retorno não será invocada se não existirem dispositivos de entrada multimídia do tipo solicitado.
Para desativar o acesso a microfones e webcams, utilize RequestPermissionCallback
como indicado abaixo:
engine.permissions().set(RequestPermissionCallback.class, (params, tell) -> {
PermissionType type = params.permissionType();
if (type == PermissionType.VIDEO_CAPTURE || type == PermissionType.AUDIO_CAPTURE) {
tell.deny();
} else {
tell.grant();
}
});
engine.permissions().set(RequestPermissionCallback::class.java,
RequestPermissionCallback { params, tell ->
val type = params.permissionType()
if (type == PermissionType.VIDEO_CAPTURE || type == PermissionType.AUDIO_CAPTURE) {
tell.deny()
} else {
tell.grant()
}
}
)
Transmissão
O Chromium tem uma funcionalidade integrada que permite a transmissão de conteúdos multimídia para dispositivos que suportam diferentes tecnologias sem fios, como Chromecast, Miracast, DLNA, AirPlay ou similares. Podem ser smart TVs, projetores e outros dispositivos.
Etapa Preliminar
Por padrão, desativamos o Chromium de procurar dispositivos multimídia na sua rede. Para ativar e permitir que o Chromium encontre os potenciais receptores, utilize a opção do Motor:
EngineOptions options = EngineOptions.newBuilder(renderingMode)
.enableMediaRouting()
.build();
Engine engine = Engine.newInstance(options);
val options = EngineOptions.newBuilder(renderingMode)
.enableMediaRouting()
.build()
val engine = Engine.newInstance(options)
Receptores Multimídia
Para começar a transmitir conteúdos multimídia para um receptor, é necessário obter um. Para este efeito, o JxBrowser fornece um serviço de perfil
separado MediaReceivers
que pode ser obtido desta forma:
MediaReceivers mediaReceivers = profile.mediaCasting().mediaReceivers();
val mediaReceivers = profile.mediaCasting().mediaReceivers()
Para saber quando um novo receptor foi descoberto, o JxBrowser fornece o evento MediaReceiverDiscovered
:
MediaReceivers mediaReceivers = profile.mediaCasting().mediaReceivers();
mediaReceivers.on(MediaReceiverDiscovered.class, event -> {
MediaReceiver receiver = event.mediaReceiver();
});
val mediaReceivers = profile.mediaCasting().mediaReceivers()
mediaReceivers.on(MediaReceiverDiscovered::class.java) { event ->
val receiver = event.mediaReceiver()
}
Para sua conveniência, o JxBrowser mantém um registro dos receptores descobertos. Se desejar obter a lista de receptores multimídia descobertos atualmente, utilize o método MediaReceivers.list()
:
MediaReceivers mediaReceivers = profile.mediaCasting().mediaReceivers();
List<MediaReceiver> receivers = mediaReceivers.list();
val mediaReceivers: MediaReceivers = profile.mediaCasting().mediaReceivers()
val receivers: List<MediaReceiver> = mediaReceivers.list()
Se estiver à procura de um receptor específico, você pode obtê-lo através do método de conveniência MediaReceivers.await(Predicate<MediaReceiver>)
. Ele aguarda até que seja descoberto o primeiro receptor que corresponda ao predicado e o retorna.
MediaReceivers mediaReceivers = profile.mediaCasting().mediaReceivers();
MediaReceiver receiver = mediaReceivers.await(it -> it.name().equals("Samsung Smart TV"));
val mediaReceivers = profile.mediaCasting().mediaReceivers()
val receiver = mediaReceivers.await { it.name() == "Samsung Smart TV" }
Para detectar que o receptor multimídia foi desconectado, ou seja, desligado ou desconectado da rede, utilize
o evento MediaReceiverDisconnected
:
receiver.on(MediaReceiverDisconnected.class, event -> {
MediaReceiver mediaReceiver = event.mediaReceiver();
});
receiver.on(MediaReceiverDisconnected::class.java) { event ->
val mediaReceiver = event.mediaReceiver()
}
Transmitindo Conteúdo
A API JxBrowser permite a conversão de conteúdos de navegadores, telas e apresentação utilizando a API de apresentação JavaScript.
Os receptores de multimídia podem suportar diferentes fontes de multimídia. Uma fonte multimídia representa um tipo de conteúdo que pode ser transmitido a um receptor multimídia. Antes de iniciar a transmissão, certifique-se de que o receptor multimídia selecionado suporta a fonte multimídia correspondente.
Criando um Navegador
Para começar a transmitir o conteúdo do navegador, utilize o método Browser.cast(MediaReceiver)
:
MediaReceiver receiver = mediaReceivers.await(it -> it.name().contains("Samsung"));
if (receiver.supports(MediaSource.browser())) {
CompletableFuture<CastSession> future = browser.cast(receiver);
}
val receiver = mediaReceivers.await { it.name().contains("Samsung")) }
if (receiver.supports(MediaSource.browser())) {
val future: CompletableFuture<CastSession> = browser.cast(receiver)
}
Cada sessão de transmissão de conteúdos multimídia para um receptor multimídia é representada por uma instância da classe CastSession
.
Request de Apresentação Padrão
Se a página Web contiver o
PresentationRequest
padrão,
o browser começa a transmitir o conteúdo especificado neste request ao invés do conteúdo do navegador.
Para verificar se o navegador contém o PresentationRequest
padrão, use:
MediaReceiver receiver = mediaReceivers.await(it -> it.name().contains("Samsung Smart TV"));
browser.defaultPresentationRequest().ifPresent(presentationRequest -> {
if (receiver.supports(presentationRequest)) {
CompletableFuture<CastSession> future = browser.cast(receiver);
}
});
val receiver = mediaReceivers.await { it.name().contains("Samsung Smart TV") }
browser.defaultPresentationRequest().ifPresent {
if (receiver.supports(it)) {
val future: CompletableFuture<CastSession> = browser.cast(receiver)
}
}
Transmitindo uma Tela
Para iniciar a transmissão do conteúdo da tela, utilize Browser.castScreen(MediaReceiver)
. Este método mostra uma caixa de diálogo padrão do Chromium
para escolher a tela a transmitir.
MediaReceiver receiver = mediaReceivers.await(it -> it.name().contains("Samsung"));
if (receiver.supports(MediaSource.screen())) {
CompletableFuture<CastSession> future = browser.castScreen(receiver);
}
val receiver = mediaReceivers.await { it.name().contains("Samsung")) }
if (receiver.supports(MediaSource.screen())) {
val future: CompletableFuture<CastSession> = browser.castScreen(receiver)
}
Se desejar selecionar a tela de forma programática, utilize o método Browser.castScreen(MediaReceiver, ScreenCastOptions)
. Encontre a tela que necessita utilizando o serviço Screens
:
MediaReceiver receiver = mediaReceivers.await(it -> it.name().contains("Samsung"));
Screen screen = profile.mediaCasting().screens().defaultScreen();
ScreenCastOptions options = ScreenCastOptions.newBuilder(screen)
.withAudio()
.build();
if (receiver.supports(MediaSource.screen())) {
CompletableFuture<CastSession> future = browser.castScreen(receiver, options);
}
val receiver = mediaReceivers.await { it.name().contains("Samsung")) }
val screen = profile.mediaCasting().screens().defaultScreen()
val options = ScreenCastOptions.newBuilder(screen)
.withAudio()
.build()
if (receiver.supports(MediaSource.screen())) {
val future: CompletableFuture<CastSession> = browser.castScreen(receiver, options)
}
Por enquanto, o Chromium suporta a transmissão de áudio apenas no Windows. Por isso, ativá-lo no macOS/Linux através de
ScreenCastOptions.Builder.withAudio()
não é uma opção. No Windows, ao selecionar a tela na caixa de diálogo do seletor, o
Chromium fornece uma caixa de verificação separada para selecionar a transmissão de áudio.
API de Apresentação
O JxBrowser permite trabalhar com API de Apresentação JavaScript.
Quando o método PresentationRequest.start()
é chamado do lado do JavaScript, o JxBrowser invoca o StartPresentationCallback
onde você pode decidir iniciar ou
cancelar a apresentação.
Para iniciar a apresentação a um receptor, utilize o método StartPresentationCallback.Action.start(MediaReceiver)
:
browser.set(StartPresentationCallback.class, (params, tell) -> {
MediaReceiver receiver = params.mediaReceivers().await(it -> {
return it.name().contains("Samsung");
});
if (receiver.supports(params.presentationRequest())) {
tell.start(receiver);
} else {
tell.cancel();
}
});
browser.set(StartPresentationCallback::class.java,
StartPresentationCallback { params, tell ->
val receiver = params.mediaReceivers().await { it.name().contains("Samsung") }
if (receiver.supports(params.presentationRequest())) {
tell.start(receiver)
} else {
tell.cancel()
}
}
)
Descobrindo Sessões de Transmissão
Para ser notificado quando uma sessão de transmissão for descoberta, o JxBrowser fornece o evento CastSessionDiscovered
:
profile.mediaCasting().castSessions().on(CastSessionDiscovered.class, event -> {
CastSession castSession = event.castSession();
});
profile.mediaCasting().castSessions().on(CastSessionDiscovered::class.java) { event ->
val castSession = event.castSession()
}
O Chromium pode descobrir sessões iniciadas por outras aplicações ou instâncias do Chromium. Para indicar que
a sessão de transmissão foi iniciada por este perfil, o JxBrowser fornece o método CastSession.isLocal()
. Assim, se uma sessão de transmissão
for iniciada por outro perfil ou mesmo outro processo do Chromium, o método retornará false
.
Interrompendo Sessões de Transmissão
Para parar uma sessão de transmissão, utilize o método CastSession.stop()
. Se desejar ser notificado quando uma sessão de transmissão tiver sido
interrompida, utilize o evento CastSessionStopped
:
CastSession session = profile.mediaCasting().castSessions().list().get(0);
session.on(CastSessionStopped.class, event -> {
// Faça algo
});
...
session.stop();
val session = profile.mediaCasting().castSessions().list().first()
session.on(CastSessionStopped::class.java) { event ->
// Faça algo
}
...
session.stop()
A sessão pode ser interrompida por outras aplicações ou instâncias do Chromium, ou seja Google Chrome. Neste caso, o evento também será invocado.
Falhas
Por vezes, o Chromium pode não conseguir iniciar uma nova sessão de transmissão, ou seja, se o receptor multimídia não for encontrado ou se o
tiver sido subitamente desconectado. Para detectar isso, use o evento CastSessionStartFailed
:
MediaReceiver receiver = mediaReceivers.await(it -> it.name().contains("Samsung"));
profile.mediaCasting().castSessions().on(CastSessionStartFailed.class, event -> {
System.out.println(event.errorMessage());
});
CompletableFuture<CastSession> future = browser.cast(receiver);
val receiver = mediaReceivers.await { it.name().contains("Samsung") }
profile.mediaCasting().castSessions().on(CastSessionStartFailed::class.java) { event ->
println(event.errorMessage())
}
val future: CompletableFuture<CastSession> = browser.cast(receiver)
Trata-se de um acontecimento intencional devido à natureza assíncrona da transmissão de mídia.
Como os métodos Browser.cast...
retornam CompletableFuture
é possível detectar que o início da sessão de transmissão
falhou. Neste caso, o JxBrowser conclui o futuro com a CastStartFailedException
:
CompletableFuture<CastSession> future = browser.cast(receiver);
future.exceptionally(throwable -> {
System.out.println(throwable.getMessage());
return null;
});
val future: CompletableFuture<CastSession> = browser.cast(receiver)
future.exceptionally { throwable ->
println(throwable.message)
null
}