Search code examples
androidhttpsmedia-player

MediaPlayer with custom socketFactory


I have a HTTPS MEDIA server with self signed certificate from which I want to stream audio in my Android app. As per this link from developer.android.com, to allow self signed certificate, I have generated a certificate by reading the .crt file, created a keystore with this certificate and initialized this keyStore to a TrustManagerFactory.

CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(getResources().openRawResource(R.raw.certificate));
Certificate ca;
try {
    ca = cf.generateCertificate(caInput);
    Log.d(TAG, "ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
    caInput.close();
}

// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);

// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);

The link describes an example to use this custom SSLContext with an HttpsURLConnection object.

// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();

But in my app for HTTP, I'm using MediaPlayer class by setting the audio link as below.

MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(address); //address is a String variable like http://example.com/audio.aac

The question is, how do i use the above SSLContext's socketFactory object with the MediaPlayer, so that the MediaPlayer could use HTTPS audio source.


Solution

  • To use this custom SSLContext connection, we have to set the socketFactory object to the HttpsURLConnection before providing the source to the media player.

    HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
    

    This allows the MediaPlayer to use the connection with our self signed certificate.

    Other than this, I also had to provide a custom HostnameVerifier implementation to verify the subjectAlternateNames manually.

    final HostnameVerifier hv =
      HttpsURLConnection.getDefaultHostnameVerifier();
    
    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
      @Override
      public boolean verify(String hostname, SSLSession session) {
        return hv.verify("www.youdomainname.com", session);
      }
    };
    

    And this custom HostnameVerifier could be linked to the MediaPlayer by the below code.

    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);