org.peterbaldwin.vlcremote.net.MediaServer.java Source code

Java tutorial

Introduction

Here is the source code for org.peterbaldwin.vlcremote.net.MediaServer.java

Source

/*-
 *  Copyright (C) 2011 Peter Baldwin   
 *  
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.peterbaldwin.vlcremote.net;

import org.apache.http.Header;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.protocol.HTTP;
import org.peterbaldwin.vlcremote.intent.Intents;
import org.peterbaldwin.vlcremote.model.Directory;
import org.peterbaldwin.vlcremote.model.Playlist;
import org.peterbaldwin.vlcremote.model.Remote;
import org.peterbaldwin.vlcremote.model.Status;
import org.peterbaldwin.vlcremote.service.StatusService;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.SystemClock;
import android.util.Log;

import java.io.IOException;
import java.net.ContentHandler;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public final class MediaServer {

    private static final String TAG = "VLC";

    private final Context mContext;

    private final String mAuthority;

    public MediaServer(Context context, String authority) {
        mContext = context;
        mAuthority = authority;
    }

    public MediaServer(Context context, Uri data) {
        mContext = context;
        mAuthority = data.getAuthority();
    }

    public String getAuthority() {
        return mAuthority;
    }

    public VLMRequest vlm() {
        return new VLMRequest(mContext, mAuthority);
    }

    public VLMRequest vlm(Uri uri) {
        return new VLMRequest(mContext, uri);
    }

    public StatusRequest status() {
        return new StatusRequest(mContext, mAuthority);
    }

    public StatusRequest status(Uri uri) {
        return new StatusRequest(mContext, uri);
    }

    public PlaylistRequest playlist(String search) {
        return new PlaylistRequest(mContext, mAuthority, search);
    }

    public BrowseRequest browse(String dir) {
        return new BrowseRequest(mContext, mAuthority, dir);
    }

    public ImageRequest image(Uri uri) {
        return new ImageRequest(mContext, uri);
    }

    public ImageRequest art() {
        return new ImageRequest(mContext, mAuthority);
    }

    static class Request {

        /**
         * Time to wait between network requests when sending multiple commands.
         */
        protected static final int DELAY = 500;

        /**
         * Time to wait (ms) for a request to complete before timing out.
         */
        protected static final int TIMEOUT = 8000;

        private final Context mContext;

        private final Uri mUri;

        protected int mFlags;

        protected boolean mNotifyPlaylist;

        protected long mDelay;

        protected Request(Context context, String authority, String path) {
            mContext = context;
            mUri = Uri.parse("http://" + authority + path);
        }

        protected Request(Context context, Uri uri) {
            mContext = context;
            mUri = uri;
        }

        protected final Intent intent(String encodedQuery) {
            Intent intent = new Intent(Intents.ACTION_STATUS);
            intent.setClass(mContext, StatusService.class);
            Uri data = mUri.buildUpon().encodedQuery(encodedQuery).build();
            intent.setData(data);
            intent.putExtra(Intents.EXTRA_FLAGS, mFlags);
            return intent;
        }

        protected final PendingIntent pending(Intent intent) {
            return PendingIntent.getService(mContext, 0, intent, 0);
        }

        protected final void start(Intent intent) {
            if (mDelay == 0L) {
                mContext.startService(intent);
            } else {
                Object service = mContext.getSystemService(Context.ALARM_SERVICE);
                AlarmManager manager = (AlarmManager) service;
                long triggerAtTime = SystemClock.elapsedRealtime() + mDelay;
                int requestCode = (int) triggerAtTime;
                int flags = 0;
                PendingIntent op = PendingIntent.getService(mContext, requestCode, intent, flags);
                manager.set(AlarmManager.ELAPSED_REALTIME, triggerAtTime, op);
            }
        }

        protected final void execute(String encodedQuery) {
            start(intent(encodedQuery));
        }

        protected final <T> Remote<T> load(ContentHandler handler) {
            String spec = mUri.toString();
            try {
                T data = (T) read(handler);
                return Remote.data(data);
            } catch (Throwable t) {
                Log.e(TAG, "Unable to load: " + spec, t);
                return Remote.error(t);
            }
        }

        @SuppressWarnings("unchecked")
        protected final <T> T read(ContentHandler handler) throws IOException {
            String spec = mUri.toString();
            URL url = new URL(spec);
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            http.setConnectTimeout(TIMEOUT);
            try {
                String usernamePassword = mUri.getUserInfo();
                if (usernamePassword != null) {
                    Header authorization = BasicScheme
                            .authenticate(new UsernamePasswordCredentials(usernamePassword), HTTP.UTF_8, false);
                    http.setRequestProperty(authorization.getName(), authorization.getValue());
                }
                return (T) handler.getContent(http);
            } finally {
                http.disconnect();
            }
        }
    }

    public static final class VLMRequest extends Request {

        VLMRequest(Context context, String authority) {
            super(context, authority, "/requests/vlm_cmd.xml");
        }

        public VLMRequest(Context context, Uri uri) {
            super(context, uri);
        }

        public final CommandInterface command = new CommandInterface();

        public final class CommandInterface {

            public final InputInterface input = new InputInterface();

            public class InputInterface {

                private InputInterface() {
                }

                public void delstream() {
                    execute("command=" + Uri.encode("del stream.sdp"));
                }

                public void stream(String input) {
                    List<String> options = Collections.emptyList();
                    stream(input, options);
                }

                public void stream(String input, List<String> options) {
                    String query = "command="
                            + Uri.encode("new stream.sdp vod enabled input \"" + input + "\" output ");
                    for (String option : options) {
                        query += Uri.encode(option);
                    }

                    execute(query);
                }
            }
        }
    }

    public static final class StatusRequest extends Request {

        StatusRequest(Context context, String authority) {
            super(context, authority, "/requests/status.xml");
        }

        public StatusRequest(Context context, Uri uri) {
            super(context, uri);
        }

        public final CommandInterface command = new CommandInterface();

        /**
         * Loads the server status synchronously.
         */
        public Remote<Status> load() {
            return load(new StatusContentHandler());
        }

        public Status read() throws IOException {
            return read(new StatusContentHandler());
        }

        /**
         * Loads the server status asynchronously.
         */
        public void get() {
            execute("");
        }

        public PendingIntent pendingGet() {
            return pending(intent(""));
        }

        public StatusRequest programmatic() {
            mFlags |= Intents.FLAG_PROGRAMMATIC;
            return this;
        }

        public StatusRequest onlyIfPlaying() {
            mFlags |= Intents.FLAG_ONLY_IF_PLAYING;
            return this;
        }

        public StatusRequest onlyIfPaused() {
            mFlags |= Intents.FLAG_ONLY_IF_PAUSED;
            return this;
        }

        public StatusRequest setResumeOnIdle() {
            mFlags |= Intents.FLAG_SET_RESUME_ON_IDLE;
            return this;
        }

        public final class CommandInterface {

            public final InputInterface input = new InputInterface();

            public class InputInterface {

                private InputInterface() {
                }

                public void play(String input) {
                    List<String> options = Collections.emptyList();
                    play(input, options);
                }

                public void play(String input, String... options) {
                    play(input, Arrays.asList(options));
                }

                public void play(String input, List<String> options) {
                    // Options are appended to the MRL
                    // for VLC 1.1.10 and earlier
                    for (String option : options) {
                        input += " " + option;
                    }
                    String query = "command=in_play&input=" + Uri.encode(input);

                    // Options are appended as query parameters
                    // for VLC 1.1.11 and later
                    for (String option : options) {
                        query += ("&option=" + Uri.encode(option));
                    }

                    execute(query);
                }

                public void enqueue(String input) {
                    execute("command=in_enqueue&input=" + Uri.encode(input));
                }
            }

            public final PlaybackInterface playback = new PlaybackInterface();

            public class PlaybackInterface {

                private PlaybackInterface() {
                }

                public void play(int id) {
                    execute("command=pl_play&id=" + id);
                }

                public void pause() {
                    execute("command=pl_pause");
                }

                public PendingIntent pendingPause() {
                    return pending(intent("command=pl_pause"));
                }

                public void stop() {
                    execute("command=pl_stop");
                }

                public void next() {
                    execute("command=pl_next");
                }

                public PendingIntent pendingNext() {
                    return pending(intent("command=pl_next"));
                }

                public void previous() {
                    execute("command=pl_previous");
                }

                public void delete(int id) {
                    mNotifyPlaylist = true;
                    execute("command=pl_delete&id=" + id);
                }

                public void empty() {
                    execute("command=pl_empty");
                }

                public void sort(int sort, int order) {
                    execute("command=pl_sort&id=" + order + "&val=" + sort);
                }

                public void shuffle() {
                    execute("command=pl_random");
                }

                public PlaybackInterface loop() {
                    execute("command=pl_loop");
                    mDelay += DELAY;
                    return this;
                }

                public PlaybackInterface repeat() {
                    execute("command=pl_repeat");
                    mDelay += DELAY;
                    return this;
                }

                public void random() {
                    execute("command=pl_random");
                }

                public void sd(String value) {
                    execute("command=pl_sd&val=" + value);
                }
            }

            public void volume(int value) {
                execute("command=volume&val=" + value);
            }

            public void adjustVolume(int amount) {
                String val = amount < 0 ? Integer.toString(amount) : "+" + amount;
                execute("command=volume&val=" + Uri.encode(val));
            }

            public void volumeDown() {
                execute("command=volume&val=-20");
            }

            public void volumeUp() {
                execute("command=volume&val=%2B20");
            }

            public void seek(String pos) {
                execute("command=seek&val=" + pos);
            }

            public void key(String keycode) {
                // Use hotkey name (without the "key-" part)
                // as the argument to simulate a hotkey press
                execute("command=key&val=" + keycode);
            }

            public void fullscreen() {
                execute("command=fullscreen");
            }

            public void shutdown() {
                execute("command=shutdown");
            }

            public void snapshot() {
                execute("command=snapshot");
            }
        }
    }

    public static final class PlaylistRequest extends Request {

        PlaylistRequest(Context context, String authority, String search) {
            super(context, authority, "/requests/playlist.xml?search=" + Uri.encode(search));
        }

        public Remote<Playlist> load() {
            return load(new PlaylistContentHandler());
        }
    }

    public static final class BrowseRequest extends Request {

        BrowseRequest(Context context, String authority, String dir) {
            super(context, authority, "/requests/browse.xml?dir=" + Uri.encode(dir));
        }

        public Remote<Directory> load() {
            return load(new DirectoryContentHandler());
        }
    }

    public static final class ImageRequest extends Request {
        ImageRequest(Context context, Uri uri) {
            super(context, uri);
        }

        ImageRequest(Context context, String authority) {
            super(context, authority, "/art");
        }

        public Bitmap read() throws IOException {
            return read(new BitmapContentHandler());
        }

        public Remote<Bitmap> load() throws IOException {
            return load(new BitmapContentHandler());
        }
    }
}