package com.miidio.audio.server;

import com.martiansoftware.jsap.FlaggedOption;
import com.martiansoftware.jsap.JSAP;
import com.martiansoftware.jsap.JSAPResult;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import java.io.*;
import java.net.ServerSocket;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

    private static Logger logger = Logger.getLogger(Main.class.getName());

    private static CaptureThread createRecorder(String mixerName) throws UnsupportedFormatException,
            LineUnavailableException {
        Mixer.Info[] mixers = AudioSystem.getMixerInfo();
        if (null == mixers || 0 == mixers.length) {
            throw new RuntimeException("no mixer found??");
        }
        Mixer.Info mixerInfo = mixers[0];
        logger.log(Level.INFO, "query mixer starting with " + mixerName);
        for (Mixer.Info info : mixers) {
            if (info.getName().startsWith(mixerName)) {
                mixerInfo = info;
            }
        }

        Mixer mixer = AudioSystem.getMixer(mixerInfo);
        AudioCapture capture = new AudioCapture();
        AudioFormat format = AudioCapture.getAudioFormat(AudioCapture.SampleRates.FORTY_FOUR_K,
                AudioCapture.Bits.SIXTEEN);
        return capture.capture(format, null, mixer);
    }

    private static ServerSocket getServerSocket(int port, String keyPath, String keyPass)
            throws NoSuchAlgorithmException, KeyStoreException, IOException,
            KeyManagementException, CertificateException, UnrecoverableKeyException {

        // we use TLS as default
        SSLContext ctx = SSLContext.getInstance("TLS");
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        KeyStore ks = KeyStore.getInstance("JKS");
        char[] passphrase = keyPass.toCharArray();
        ks.load(new FileInputStream(new File(keyPath)), passphrase);
        kmf.init(ks, passphrase);
        ctx.init(kmf.getKeyManagers(), null, null);
        ServerSocket ss = ctx.getServerSocketFactory().createServerSocket(port);
        ss.setPerformancePreferences(1, 2, 0);
        return ss;
    }

    private static void startServer(String keyPath, String keyPass, int port, String mixerName,
                                    String password) throws Exception {

        AudioSocket socket = new AudioSocket(getServerSocket(port, keyPath, keyPass), password);
        final CaptureThread capturer = createRecorder(mixerName);
        socket.addEventListener(new AudioSocket.Listener() {
            @Override
            public void onConnected(InputStream is, OutputStream os) {
                // This is the first prototype, we should compress the audio stream before
                // sending.
                capturer.setOutputStream(os);
            }

            @Override
            public void onDisconnected() {
                capturer.setOutputStream(null);
            }
        });
        socket.start();
    }

    public static void main(String[] args) throws Exception {
        JSAP jsap = new JSAP();
        jsap.registerParameter(new FlaggedOption("mixer")
                .setStringParser(JSAP.STRING_PARSER)
                .setDefault("kuwatec")
                .setShortFlag('m')
                .setLongFlag("mixer")
                .setHelp("The audio loopback driver name. We will use this name to query mixer device."));

        jsap.registerParameter(new FlaggedOption("port")
                .setStringParser(JSAP.INTEGER_PARSER)
                .setDefault("13579")
                .setShortFlag('p')
                .setLongFlag("port")
                .setHelp("server port"));

        jsap.registerParameter(new FlaggedOption("password")
                .setStringParser(JSAP.STRING_PARSER)
                .setRequired(false)
                .setShortFlag('P')
                .setLongFlag("password")
                .setHelp("The password to control and listen your computer"));
        jsap.registerParameter(new FlaggedOption("key-path")
                .setStringParser(JSAP.STRING_PARSER)
                .setRequired(true)
                .setShortFlag('K')
                .setLongFlag("key-path")
                .setHelp("The path to control and listen your computer"));
        jsap.registerParameter(new FlaggedOption("key-pass")
                .setStringParser(JSAP.STRING_PARSER)
                .setRequired(true)
                .setShortFlag('k')
                .setLongFlag("key-pass")
                .setHelp("The password to control and listen your computer"));

        JSAPResult opts = jsap.parse(args);

        if (!opts.success()) {
            System.err.println();
            System.err.println("Usage: java " + Main.class.getName());
            System.err.println("                " + jsap.getUsage());
            System.err.println();
            System.err.println(jsap.getHelp());
            System.exit(1);
        } else if (opts.getInt("port") < 1 || opts.getInt("port") > 65535) {
            System.err.println("port should between 1 and 65535");
            System.exit(2);
        }
        startServer(opts.getString("key-path"),
                opts.getString("key-pass"),
                opts.getInt("port"),
                opts.getString("mixer"),
                opts.getString("password", null));
    }
}

@@ -157,16 +157,54 @@
 esult;%0A%0A
+import javax.net.ServerSocketFactory;%0A
 import j
@@ -227,32 +227,32 @@
 ManagerFactory;%0A
-
 import javax.net
@@ -1862,32 +1862,181 @@
 KeyException %7B%0A%0A
+        if (null == keyPath %7C%7C null == keyPass) %7B%0A            return ServerSocketFactory.getDefault().createServerSocket(port);%0A        %7D else %7B%0A    
         // we us
@@ -2060,16 +2060,20 @@
         
+ 
+   
 SSLConte
@@ -2108,24 +2108,28 @@
 nce(%22TLS%22);%0A
+    
         KeyM
@@ -2198,16 +2198,20 @@
         
+    
 KeyStore
@@ -2253,16 +2253,20 @@
         
+  
+  
 char%5B%5D p
@@ -2296,24 +2296,28 @@
 harArray();%0A
+    
         ks.l
@@ -2381,16 +2381,20 @@
         
+    
 kmf.init
@@ -2419,16 +2419,20 @@
         
+  
+  
 ctx.init
@@ -2463,24 +2463,28 @@
 ull, null);%0A
+    
         Serv
@@ -2560,16 +2560,20 @@
         
+    
 ss.setPe
@@ -2607,24 +2607,28 @@
 0);%0A        
+  
+  
 return ss;%0A 
@@ -2626,16 +2626,26 @@
 urn ss;%0A
+        %7D%0A
     %7D%0A%0A 
@@ -4590,43 +4590,8 @@
 ER)%0A
-                .setRequired(true)%0A
     
@@ -4855,43 +4855,8 @@
 ER)%0A
-                .setRequired(true)%0A
     
@@ -5165,32 +5165,29 @@
 ava 
-%22 + Main.class.getName()
+-jar AudioServer.jar%22
 );%0A 

make secure connection as optional