Git Product home page Git Product logo

ocast-jvm's Introduction

OCast-JVM

Licence
Build status
Documentation

The Orange OCast SDK provides all required API methods to implement cast applications to interact with an OCast device.

The sample project aims to demonstrate the basic instruction set of the Orange OCast SDK to help you get started.

Installation

Retrieve the source code to build the project by cloning the repository:

git clone https://github.com/Orange-OpenSource/OCast-JVM.git

Usage

1. Register your device type

You have to register your device type into the DeviceCenter.

๐Ÿ”ธ Java

DeviceCenter deviceCenter = new DeviceCenter();
deviceCenter.registerDevice(ReferenceDevice.class);

๐Ÿ”น Kotlin

val deviceCenter = DeviceCenter()
deviceCenter.registerDevice(ReferenceDevice::class.java)

2. Discovering devices

You need to call the resumeDiscovery() method to start the device discovery. Then you can be informed by the DeviceCenter by adding a DeviceListener.

If devices are found on your network, the onDevicesAdded(@NotNull List<? extends Device> devices) method is called.

If devices are lost (network problem or device is turned-off), the onDevicesRemoved(@NotNull List<? extends Device> devices) method is called.

๐Ÿ”ธ Java

deviceCenter.addDeviceListener(this);
deviceCenter.resumeDiscovery();

// DeviceListener methods
@Override
public void onDevicesAdded(@NotNull List<? extends Device> devices) {}
@Override
public void onDevicesRemoved(@NotNull List<? extends Device> devices) {}
@Override
public void onDiscoveryStopped(@Nullable Throwable error) {}

๐Ÿ”น Kotlin

deviceCenter.addDeviceListener(this)
deviceCenter.resumeDiscovery()

// DeviceListener methods
override fun onDevicesAdded(devices: List<Device>) {}
override fun onDevicesRemoved(devices: List<Device>) {}
override fun onDiscoveryStopped(error: Throwable?) {}

You can stop the device discovery by calling the stopDiscovery() method. This will call the onDiscoveryStopped(@Nullable Throwable error) method. The list of discovered devices will be cleaned, so if you want to keep them you should call pauseDiscovery() instead. This is useful to manage application background state.

If a network error occurs, the onDiscoveryStopped(@Nullable Throwable error) method is called but the error parameter is filled with the issue reason.

By default, the list of devices is refreshed every 30 seconds. You can decrease this interval by setting the discoveryInterval property. You should do this when the list of devices is displayed and restore the default value later.

3. Connect to the device

To connect to the device and use OCast media commands on your own application, you must set the device applicationName property. Once you are connected to the device, the application is started automatically when you send a media command. You can also manage the application state manually. See Manage application state.

๐Ÿ”ธ Java

device.setApplicationName("MyWebApp");

๐Ÿ”น Kotlin

device.applicationName = "MyWebApp"

If you want to perform a secure connection, you can set an SSLConfiguration object with your custom settings. Then you must call the connect(sslConfiguration: SSLConfiguration?, onSuccess: Runnable, onError: Consumer<OCastError>) method. Once either onSuccess or onError is called, you can send commands to your device.

๐Ÿ”ธ Java

SSLConfiguration sslConfiguration = new SSLConfiguration(trustManager, socketFactory, hostnameVerifier);
device.connect(sslConfiguration, () -> {
    // Send commands
}, oCastError -> {
    // Manage connection errors
});

๐Ÿ”น Kotlin

val sslConfiguration = SSLConfiguration(trustManager, socketFactory, hostnameVerifier)
device.connect(sslConfiguration, {
    // Send commands
}, { oCastError ->
    // Manage connection errors
})

You can disconnect from the device using the disconnect(@NotNull Runnable onSuccess, @NotNull Consumer<OCastError> onError) method. This is useful to manage application background state.

If a network error occurs, the onDeviceDisconnected(@NotNull Device device, @Nullable Throwable error) method of DeviceListener is called with the issue reason.

4. Send OCast commands

You can use the OCast commands provided by the SDK in the Device abstract class. The command list is described here.

๐Ÿ”ธ Java

PrepareMediaCommandParams params = new PrepareMediaCommandParams(
        "http://myMovie.mp4",
        1,
        "Movie Sample",
        "OCast",
        "",
        Media.Type.VIDEO,
        Media.TransferMode.STREAMED,
        true
);
device.prepareMedia(params, null, () -> {}, oCastError -> {});

๐Ÿ”น Kotlin

val params = PrepareMediaCommandParams(
    "http://myMovie.mp4",
    1,
    "Movie Sample",
    "OCast",
    "",
    Media.Type.VIDEO,
    Media.TransferMode.BUFFERED,
    true
)
device.prepareMedia(params, null, {}, {})

5. Receive OCast events

The device can send events defined in the OCast protocol. The various methods of the EventListener interface will be called depending on the event.

๐Ÿ”ธ Java

deviceCenter.addEventListener(this);

// EventListener methods
@Override
public void onMediaPlaybackStatus(@NotNull Device device, @NotNull MediaPlaybackStatus mediaPlaybackStatus) {}
@Override
public void onMediaMetadataChanged(@NotNull Device device, @NotNull MediaMetadata mediaMetadata) {}
@Override
public void onUpdateStatus(@NotNull Device device, @NotNull UpdateStatus updateStatus) {}
@Override
public void onVolumeChanged(@NotNull Device device, @NotNull Volume volume) {}

๐Ÿ”น Kotlin

deviceCenter.addEventListener(this)

// EventListener methods
override fun onMediaPlaybackStatus(device: Device, mediaPlaybackStatus: MediaPlaybackStatus) {}
override fun onMediaMetadataChanged(device: Device, mediaMetadata: MediaMetadata) {}
override fun onUpdateStatus(device: Device, updateStatus: UpdateStatus) {}
override fun onVolumeChanged(device: Device, volume: Volume) {}

6. Send custom commands

If you need to send a command not defined in the OCast protocol, you can use the send(@NotNull OCastApplicationLayer<T> message, @NotNull OCastDomain domain, @NotNull Runnable onSuccess, @NotNull Consumer<OCastError> onError) method (or its Consumer counterpart) of the Device abstract class. The custom command must subclass OCastCommandParams.

๐Ÿ”ธ Java

class CustomCommandParams extends OCastCommandParams {

    @NotNull
    private String myParameter;

    public CustomCommandParams(@NotNull String myParameter) {
        super("customCommand");
        this.myParameter = myParameter;
    }

    @NotNull
    public String getMyParameter() {
        return myParameter;
    }
}

class CustomReplyParams {

    @NotNull
    private String myValue;

    public CustomReplyParams(@NotNull String myValue) {
        this.myValue = myValue;
    }

    @NotNull
    public String getMyValue() {
        return myValue;
    }
}

OCastDataLayer<OCastCommandParams> data = new CustomCommandParams("paramValue").build();
OCastApplicationLayer<OCastCommandParams> message = new OCastApplicationLayer<>("CustomService", data);
device.send(message, OCastDomain.BROWSER, CustomReplyParams.class, customReplyParams -> {
    // ...
}, oCastError -> {
    // ...
});

๐Ÿ”น Kotlin

class CustomCommandParams(val myParameter: String) : OCastCommandParams("customCommand")
class CustomReplyParams(val myValue: String)

val data = CustomCommandParams("paramValue").build()
val message = OCastApplicationLayer("CustomService", data)
device.send(message, OCastDomain.BROWSER, CustomReplyParams::class.java, { customReplyParams ->
    // ...
}, { oCastError ->
    // ...
})

Please note that the Orange OCast SDK uses Jackson under the hood. Thus you can use Jackson annotations when defining your custom commands and replies if needed.

7. Receive custom events

If you need to receive an event not defined in the OCast protocol, you can override the onCustomEvent(@NotNull Device device, @NotNull String name, @NotNull String params) method of the EventListerner interface.

๐Ÿ”ธ Java

class CustomEvent {

    @NotNull
    private String myEventValue;

    public CustomEvent(@NotNull String myEventValue) {
        this.myEventValue = myEventValue;
    }

    @NotNull
    public String getMyEventValue() {
        return myEventValue;
    }
}

@Override
public void onCustomEvent(@NotNull Device device, @NotNull String name, @NotNull String params) {
    try {
        CustomEvent customEvent = JsonTools.INSTANCE.decode(params, CustomEvent.class);
        // ...
    } catch (Exception e) {
        e.printStackTrace();
    }
}

๐Ÿ”น Kotlin

class CustomEvent(val myEventValue: String)

override fun onCustomEvent(device: Device, name: String, params: String) {
    try {
        val customEvent = JsonTools.decode<CustomEvent>(params)
        // ...
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

8. Manage application state

You can manage the application state manually. The startApplication(@NotNull Runnable onSuccess, @NotNull Consumer<OCastError> onError) method starts the application identified by the applicationName property whereas the stopApplication(@NotNull Runnable onSuccess, @NotNull Consumer<OCastError> onError) method stops it.

9. Android media route module

If you are using the Orange OCast SDK on Android, you may optionally use the OCast media route module. This module allows you to take advantage of the native Android MediaRouter framework when interacting with OCast devices.

You do not need to manipulate any instance of DeviceCenter when using the OCast media route module. You use the OCastMediaRouteHelper instead, and devices are wrapped into instances of MediaRouter.RouteInfo.

To use the Android media route module, simply initialize the OCastMediaRouteHelper singleton with the list of device types you want to detect, and register a MediaRouter.Callback to be notified of the various MediaRouter events:

๐Ÿ”ธ Java

OCastMediaRouteHelper.INSTANCE.initialize(this, Arrays.asList(ReferenceDevice.class));
OCastMediaRouteHelper.addMediaRouterCallback(mediaRouterCallback)

// MediaRouter.Callback methods
@Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo route) {
    Device device = OCastMediaRouteHelper.INSTANCE.getDeviceFromRoute(route);
    if (device != null) {
        // Set applicationName property and connect to the device
    }
}
@Override
public void onRouteUnselected(MediaRouter router, int type, MediaRouter.RouteInfo info) {}
@Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {}
@Override
public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {}
@Override
public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {}

๐Ÿ”น Kotlin

OCastMediaRouteHelper.initialize(this, listOf(ReferenceDevice::class.java))
OCastMediaRouteHelper.addMediaRouterCallback(mediaRouterCallback)

// MediaRouter.Callback methods
override fun onRouteSelected(router: MediaRouter?, route: MediaRouter.RouteInfo?) {
    OCastMediaRouteHelper.getDeviceFromRoute(route)?.run {
        // Set applicationName property and connect to the device
    }
}
override fun onRouteUnselected(mediaRouter: MediaRouter?, route: MediaRouter.RouteInfo?) {}
override fun onRouteRemoved(router: MediaRouter?, route: MediaRouter.RouteInfo?) {}
override fun onRouteAdded(router: MediaRouter?, route: MediaRouter.RouteInfo?) {}
override fun onRouteChanged(router: MediaRouter?, route: MediaRouter.RouteInfo?) {}

As with DeviceCenter, it is also possible to add an EventListener to receive OCast events:

๐Ÿ”ธ Java

OCastMediaRouteHelper.INSTANCE.addEventListener(this);

// EventListener methods
@Override
public void onMediaPlaybackStatus(@NotNull Device device, @NotNull MediaPlaybackStatus mediaPlaybackStatus) {}
@Override
public void onMediaMetadataChanged(@NotNull Device device, @NotNull MediaMetadata mediaMetadata) {}
@Override
public void onUpdateStatus(@NotNull Device device, @NotNull UpdateStatus updateStatus) {}

๐Ÿ”น Kotlin

OCastMediaRouteHelper.addEventListener(this)
override fun onMediaPlaybackStatus(device: Device, mediaPlaybackStatus: MediaPlaybackStatus) {}
override fun onMediaMetadataChanged(device: Device, mediaMetadata: MediaMetadata) {}
override fun onUpdateStatus(device: Device, updateStatus: UpdateStatus) {}

The MediaRouter framework allows you to display a dialog with the list of detected media routes. To do so you need to create an XML file with the content hereafter and implement the onCreateOptionsMenu(Menu menu) method of your activity:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/item_all_media_route"
        android:title="@string/all_media_route"
        app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
        app:showAsAction="always" />

</menu>

๐Ÿ”ธ Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);

    getMenuInflater().inflate(R.menu.my_menu, menu);
    MenuItem mediaRouteMenuItem = menu.findItem(R.id.item_all_media_route);
    MediaRouteActionProvider actionProvider = (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
    actionProvider.setRouteSelector(OCastMediaRouteHelper.INSTANCE.getMediaRouteSelector());

    return true;
}

๐Ÿ”น Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)

    menuInflater.inflate(R.menu.my_menu, menu)
    val mediaRouteMenuItem = menu.findItem(R.id.item_all_media_route)
    val actionProvider = MenuItemCompat.getActionProvider(mediaRouteMenuItem) as MediaRouteActionProvider
    actionProvider.routeSelector = OCastMediaRouteHelper.mediaRouteSelector

    return true
}

The Android media route module automatically sets the discoverInterval property of the underlying DeviceCenter to its minimum value when the media route selection dialog is displayed, and sets it back to its default value when the dialog is dismissed.

Sample applications

Both Java and Kotlin desktop sample applications as well as a Kotlin Android application are available.

Logs

The Orange OCast SDK includes specific log messages which can be enabled by changing the DEBUG constant of the OCastLog.Companion class to true and by recompiling the SDK.

The level property of the OCastLog.Companion class controls the logging output. The default value is OFF.

The logs rely on the native Java logging framework, thus you will need to configure the log level of your handlers. If you are working on Android, you will also need to type the following command in a terminal to enable logs with level lower than INFO:

adb shell setprop log.tag.WebSocket VERBOSE

Where WebSocket should be replaced by the name of the class which contains the logs to display.

Please note that logs are not enabled on JFrog Bintray releases.

Author

Orange (Thierry Tassain (deuttai) and Florent Maitre)

License

OCast is licensed under the Apache v2 License. See the LICENSE file for more info.

ocast-jvm's People

Contributors

florentmaitre avatar slafon avatar ttassain avatar twear81 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ocast-jvm's Issues

OCast-Java not compatible with Android 10 devices?

Hello,

we are still using deprecated version of your package: https://github.com/Orange-OpenSource/OCast-Java but I cannot report an issue there since it is deprecated.

Is it possible, that the deprecated package is not compatible with Android 10? E.g. I already had to update the way we connect to OCast stick, because our code was incompatible with Android 10.

I can connect to it as I would connect to any other wifi from our app. But I cannot start pairing.

To be specific, public void onDeviceAdded(DiscoveredDevice device) from org.ocast.discovery.Discovery does not get triggered, when I try to pair Android 10 device.

I will be fine with "you need to upgrade to non deprecated version" kind of response. At least we will be forced to upgrade to non deprecated version as soon as possible.

Best Regards
Daniel

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.