Bose is offering a line of speakers that have REST API.
This project offers an API implemented in Java in to the seamlessly interact with the Speakers using Java or Android applications.
The API is built and tested with and for a Bose SoundTouch 20 with Firmware Version 19.0.5.42017.2794643.
Simply add the dependency
<dependency>
<groupId>org.soundtouch4j</groupId>
<artifactId>soundtouch4j-api</artifactId>
<version>1.0.8-SNAPSHOT</version>
</dependency>
This will add the Google HTTP Client and the XML Implementation to your project
Similar to the Maven Project, we include the JAR, but exclude some binaries that are shipped with the Google Client Lib.
implementation ('org.soundtouch4j:soundtouch4j-api:1.0.7') {
exclude module: 'httpclient'
exclude module: 'xpp3'
exclude module: 'commons-logging'
}
- Update to Firmware Version 21.x of Bose SoundTouch Speaker
- Update to Firmware Version 20.x of Bose SoundTouch Speaker
- Update to Google HTTP Lib 1.27.0 (and therefore be able to remove guava again)
- Update to Junit 5
- Update to Google HTTP Lib 1.26.0
- Update
/group
endpoint and add check for Version and Product Type
- Adding Checks in the Set-Endpoints on the Response that is received from the Speaker
- Increase Test Coverage
- Adding CI and Code Inspection via SonarCloud
Adding Endpoint
/getGroup
/getZone
/setZone
/addZoneSlave
/removeZoneSlave
Adding Endpoint
/bass
/bassCapabilities
Adding Endpoint
/name
Available Endpoints
/info
/key
/nowplaying
/preset
/select
/source
/volume
The methods in the Implementation mirror 1:1 the behavior of the REST API of the Speaker.
Library is compiled for Java 6, so it can be used easily on Android as well.
In order to use a dynamic URL for your speaker, please have look on the SsdpScanner in the Tests.
// Create a SoundTouch instance to communicate with your speaker
final SoundTouch soundTouchApi = new SoundTouchApi("http://soudntouch.sample.net", new NetHttpTransport());
// If the speaker is not on, turn it on
if (soundTouchApi.getNowPlayingApi().nowPlaying().isInStandbyMode()) {
soundTouchApi.getKeyApi().power();
}
// Create a SoundTouch instance to communicate with your speaker
final SoundTouch soundTouchApi = new SoundTouchApi("http://soudntouch.sample.net", AndroidHttp.newCompatibleTransport());
// If the speaker is not on, turn it on
if (soundTouchApi.getNowPlayingApi().nowPlaying().isInStandbyMode()) {
soundTouchApi.getKeyApi().power();
}
For the REST Calls ST4J is using the Google HTTP Client. The XML Support on this library is beta, but it works like a charm.
This is a helpful example for the XML Usage of the Lib.
- https://github.com/google/google-http-java-client/blob/dev/google-http-client-xml/src/test/java/com/google/api/client/xml/XmlTest.java
- https://stackoverflow.com/questions/14751115/sending-post-request-using-com-google-api-client-http-httprequest-object-in-goog
There is an Issue with with XPP on Android and on J2SE, so there is a Hack in SoundTouchApiClient.java
The Google HTTP Client comes with a simple mock, that allows us to test all the request in a nice fashion.
- https://github.com/googleapis/google-http-java-client/blob/dev/google-http-client/src/test/java/com/google/api/client/http/HttpResponseTest.java
- https://github.com/googleapis/google-http-java-client/blob/dev/google-http-client/src/test/java/com/google/api/client/http/HttpRequestTest.java
For the SSDP Implementation we use ResourcePools SSDP's Implementation. If you can to make use of their implementation too, add this
<dependency>
<groupId>io.resourcepool</groupId>
<artifactId>ssdp-client</artifactId>
<version>2.2.0</version>
</dependency>
or on Android
implementation 'io.resourcepool:ssdp-client:2.2.0'
For the Async Operations in the Tests there Awaitility is used: https://github.com/awaitility/awaitility
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>3.1.2</version>
<scope>test</scope>
</dependency>
Sample method for scanning for devices.
public static synchronized List<SsdpService> synchronousBlockingDeviceScanner(final int timeToScanInMilliseconds) {
final String boseUrn = "urn:schemas-upnp-org:device:MediaRenderer:1";
final SsdpClient client = SsdpClient.create();
final List<SsdpService> servicesFound = new ArrayList<SsdpService>();
final DiscoveryRequest networkStorageDevice = DiscoveryRequest.builder()
.serviceType(boseUrn)
.build();
client.discoverServices(networkStorageDevice, new DiscoveryListener() {
@Override
public void onServiceDiscovered(final SsdpService service) {
System.out.println("Found service at IP: " + service.getRemoteIp()
.toString());
servicesFound.add(service);
}
@Override
public void onServiceAnnouncement(final SsdpServiceAnnouncement announcement) {
System.out.println("Service announced something: " + announcement);
}
@Override
public void onFailed(final Exception ex) {
System.out.println("Service onFailed: " + ex.getMessage());
}
});
// ... wait
System.out.println("Discovery Stopped and Serives Found: " + servicesFound.size());
client.stopDiscovery();
return servicesFound;
}
Copyright 2018 Gerald Madlmayr
Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
https://opensource.org/licenses/MIT
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.