| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you under the Apache License, Version 2.0 (the | |
| // "License"); you may not use this file except in compliance | |
| // with the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, | |
| // software distributed under the License is distributed on an | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| // KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations | |
| // under the License. | |
| package vncclient.vnc; | |
| import streamer.ByteBuffer; | |
| import streamer.Element; | |
| import streamer.Link; | |
| import streamer.OneTimeSwitch; | |
| import streamer.Pipeline; | |
| import streamer.PipelineImpl; | |
| import streamer.debug.MockSink; | |
| import streamer.debug.MockSource; | |
| import common.ScreenDescription; | |
| public class VncInitializer extends OneTimeSwitch { | |
| // Pad names | |
| public static final String CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD = "encodings"; | |
| public static final String CLIENT_PIXEL_FORMAT_ADAPTER_PAD = "pixel_format"; | |
| protected byte sharedFlag = RfbConstants.EXCLUSIVE_ACCESS; | |
| /** | |
| * Properties of remote screen . | |
| */ | |
| protected ScreenDescription screen; | |
| public VncInitializer(String id, boolean shared, ScreenDescription screen) { | |
| super(id); | |
| setSharedFlag(shared); | |
| this.screen = screen; | |
| declarePads(); | |
| } | |
| @Override | |
| protected void declarePads() { | |
| super.declarePads(); | |
| outputPads.put(CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, null); | |
| outputPads.put(CLIENT_PIXEL_FORMAT_ADAPTER_PAD, null); | |
| } | |
| public ScreenDescription getScreen() { | |
| return screen; | |
| } | |
| public void setScreen(ScreenDescription screen) { | |
| this.screen = screen; | |
| } | |
| public void setSharedFlag(boolean shared) { | |
| if (shared) | |
| sharedFlag = RfbConstants.SHARED_ACCESS; | |
| else | |
| sharedFlag = RfbConstants.EXCLUSIVE_ACCESS; | |
| } | |
| @Override | |
| protected void handleOneTimeData(ByteBuffer buf, Link link) { | |
| if (verbose) | |
| System.out.println("[" + this + "] INFO: Data received: " + buf + "."); | |
| // Server initialization message is at least 24 bytes long + length of | |
| // desktop name | |
| if (!cap(buf, 24, UNLIMITED, link, false)) | |
| return; | |
| // Read server initialization message | |
| // Read frame buffer size | |
| int framebufferWidth = buf.readUnsignedShort(); | |
| int framebufferHeight = buf.readUnsignedShort(); | |
| // Read pixel format | |
| int bitsPerPixel = buf.readUnsignedByte(); | |
| int depth = buf.readUnsignedByte(); | |
| int bigEndianFlag = buf.readUnsignedByte(); | |
| int trueColorFlag = buf.readUnsignedByte(); | |
| int redMax = buf.readUnsignedShort(); | |
| int greenMax = buf.readUnsignedShort(); | |
| int blueMax = buf.readUnsignedShort(); | |
| int redShift = buf.readUnsignedByte(); | |
| int greenShift = buf.readUnsignedByte(); | |
| int blueShift = buf.readUnsignedByte(); | |
| // Skip padding | |
| buf.skipBytes(3); | |
| // Read desktop name | |
| int length = buf.readSignedInt(); | |
| // Consume exactly $length bytes, push back any extra bytes | |
| if (!cap(buf, length, length, link, true)) | |
| return; | |
| String desktopName = buf.readString(length, RfbConstants.US_ASCII_CHARSET); | |
| buf.unref(); | |
| if (verbose) | |
| System.out.println("[" + this + "] INFO: Desktop name: \"" + desktopName + "\", bpp: " + bitsPerPixel + ", depth: " + depth + ", screen size: " | |
| + framebufferWidth + "x" + framebufferHeight + "."); | |
| // Set screen properties | |
| screen.setFramebufferSize(framebufferWidth, framebufferHeight); | |
| screen.setPixelFormat(bitsPerPixel, depth, bigEndianFlag != RfbConstants.LITTLE_ENDIAN, trueColorFlag == RfbConstants.TRUE_COLOR, redMax, greenMax, blueMax, redShift, | |
| greenShift, blueShift); | |
| screen.setDesktopName(desktopName); | |
| // If sever screen has different parameters than ours, then change it | |
| if (!screen.isRGB888_32_LE()) { | |
| // Send client pixel format | |
| sendClientPixelFormat(); | |
| } | |
| // Send encodings supported by client | |
| sendSupportedEncodings(); | |
| switchOff(); | |
| } | |
| @Override | |
| protected void onStart() { | |
| ByteBuffer buf = new ByteBuffer(new byte[] {sharedFlag}); | |
| pushDataToOTOut(buf); | |
| } | |
| private void sendClientPixelFormat() { | |
| pushDataToPad(CLIENT_PIXEL_FORMAT_ADAPTER_PAD, new ByteBuffer(0)); | |
| } | |
| private void sendSupportedEncodings() { | |
| pushDataToPad(CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, new ByteBuffer(0)); | |
| } | |
| @Override | |
| public String toString() { | |
| return "VncInit(" + id + ")"; | |
| } | |
| /** | |
| * Example. | |
| */ | |
| public static void main(String args[]) { | |
| System.setProperty("streamer.Element.debug", "true"); | |
| final String desktopName = "test"; | |
| Element source = new MockSource("source") { | |
| { | |
| bufs = ByteBuffer.convertByteArraysToByteBuffers( | |
| // Send screen description | |
| new byte[] { | |
| // Framebuffer width (short) | |
| 0, (byte)200, | |
| // Framebuffer height (short) | |
| 0, 100, | |
| // Bits per pixel | |
| 32, | |
| // Depth, | |
| 24, | |
| // Endianness flag | |
| RfbConstants.LITTLE_ENDIAN, | |
| // Truecolor flag | |
| RfbConstants.TRUE_COLOR, | |
| // Red max (short) | |
| 0, (byte)255, | |
| // Green max (short) | |
| 0, (byte)255, | |
| // Blue max (short) | |
| 0, (byte)255, | |
| // Red shift | |
| 16, | |
| // Green shift | |
| 8, | |
| // Blue shift | |
| 0, | |
| // Padding | |
| 0, 0, 0, | |
| // Desktop name length (int) | |
| 0, 0, 0, 4, | |
| // Desktop name ("test", 4 bytes) | |
| 't', 'e', 's', 't', | |
| // Tail | |
| 1, 2, 3 | |
| }, | |
| // Tail packet | |
| new byte[] {4, 5, 6}); | |
| } | |
| }; | |
| ScreenDescription screen = new ScreenDescription(); | |
| final VncInitializer init = new VncInitializer("init", true, screen); | |
| Element initSink = new MockSink("initSink") { | |
| { | |
| // Expect shared flag | |
| bufs = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {RfbConstants.SHARED_ACCESS}); | |
| } | |
| }; | |
| Element mainSink = new MockSink("mainSink") { | |
| { | |
| // Expect two tail packets | |
| bufs = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3}, new byte[] {4, 5, 6}); | |
| } | |
| }; | |
| ByteBuffer[] emptyBuf = ByteBuffer.convertByteArraysToByteBuffers(new byte[] {}); | |
| Element encodingsSink = new MockSink("encodings", emptyBuf); | |
| Element pixelFormatSink = new MockSink("pixel_format", emptyBuf); | |
| Pipeline pipeline = new PipelineImpl("test"); | |
| pipeline.addAndLink(source, init, mainSink); | |
| pipeline.add(encodingsSink, pixelFormatSink, initSink); | |
| pipeline.link("init >otout", "initSink"); | |
| pipeline.link("init >" + CLIENT_SUPPORTED_ENCODINGS_ADAPTER_PAD, "encodings"); | |
| pipeline.link("init >" + CLIENT_PIXEL_FORMAT_ADAPTER_PAD, "pixel_format"); | |
| pipeline.runMainLoop("source", STDOUT, false, false); | |
| if (!screen.isRGB888_32_LE()) | |
| System.err.println("Screen description was read incorrectly: " + screen + "."); | |
| if (!desktopName.equals(screen.getDesktopName())) | |
| System.err.println("Screen desktop name was read incorrectly: \"" + screen.getDesktopName() + "\"."); | |
| } | |
| } |