Latest 0.9.0
License Apache-2.0
Platforms ios 10.0, tvos 10.0, osx 10.12, requires ARC
Dependencies RxSwift, RxCocoa, RxSSDP, AEXML

Swift 4.1
Travis Badge
Test Coverage
CocoaPods Version Badge
License Badge

Swift library that simplifies interacting with Sonos Devices


  • [x] GET SSDP devices on the current network
  • [x] MAP SSDP devices into Sonos Rooms
  • [x] MAP Sonos Rooms into Sonos Groups + renew
  • [x] GET now playing track per room (supports Spotify, Tunein, Library & TV) + renew
  • [x] DOWNLOAD track image
  • [x] GET group progress + renew
  • [x] GET group queue
  • [ ] ADD tracks to the group queue
  • [ ] DELETE tracks from the group queue
  • [x] SET previous/next group queue track
  • [x] SET play/pause/stop current track
  • [x] GET group volume
  • [x] SET group volume


  • [x] iOS
  • [x] MacOS
  • [x] tvOS

This library requires Swift 4.1 & RxSwift.

Background Info

The first version of this project started as a way to understand Sonos better. This version is here to help me improve my RxSwift knowledge.


Inspect SonosInteractor.swift this class is your entry to the library.

From here, continue by chaining observerable functions specified in the matching models Group.swift, Room.swift & Track.swift


.subscribe(onNext: { (queue) in
    print("queue: onNext")
}, onError: { (error) in
    print("queue: (error.localizedDescription)")
}, onCompleted: {
    print("queue: onCompleted")
}).disposed(by: disposeBag)

Framework entry point

Start with a static function in the SonosInteractor

open class SonosInteractor {

   static func setActive(group: Group)

   static func getActiveGroup() -> Observable<Group>

    static func getAllGroups() -> Observable<[Group]>

Observable chain methods

The continue with one or multiple chain methods.

Methods for an Observable Group:

extension ObservableType where E == Group {

    func getRooms() -> Observable<[Room]>

    func getTrack() -> Observable<Track?>

    func getImage() -> Observable<Data?>

    func getProgress() -> Observable<GroupProgress>

    func getQueue() -> Observable<[Track]>

    func getTransportState() -> Observable<(TransportState, MusicService)>

    func set(transportState: TransportState) -> Observable<TransportState>

    func getVolume() -> Observable<Int>

    func set(volume: Int) -> Observable<Int>

    func setNextTrack() -> Observable<Swift.Void>

    func setPreviousTrack() -> Observable<Swift.Void>

    func getMute() -> Observable<[Bool]>

    func set(mute enabled: Bool) -> Observable<[Bool]>

Methods for an Observable Track:

extension ObservableType where E == Track {

    func getImage() -> Observable<Data?>

Methods for an Observable array with Room’s:

extension ObservableType where E == [Room] {

    func getMute() -> Observable<[Bool]>

    func set(mute enabled: Bool) -> Observable<[Bool]>

Methods for an Observable Room:

extension ObservableType where E == Room {

    func getMute() -> Observable<Bool>

    func set(mute enabled: Bool) -> Observable<Bool>

Modify settings

Inspect SonosSettings.swift, this class contains all customizable settings.

More demos?

Clone the repository, open xcworkspace and build the demo project

Development Info

Please document code changes in unit tests and make sure all tests are green.


This project is released under the Apache-2.0 license.

Latest podspec

    "name": "RxSonosLib",
    "version": "0.9.0",
    "license": {
        "type": "Apache-2.0"
    "homepage": "",
    "authors": {
        "Stefan Renne": "[email protected]"
    "summary": "RxSwift library that simplifies interacting with Sonos Devices",
    "source": {
        "git": "",
        "tag": "0.9.0"
    "swift_version": "4.1",
    "platforms": {
        "ios": "10.0",
        "tvos": "10.0",
        "osx": "10.12"
    "requires_arc": true,
    "source_files": "RxSonosLib/Framework/**/*.swift",
    "dependencies": {
        "RxSwift": [
            "~> 4.1"
        "RxCocoa": [
            "~> 4.1"
        "RxSSDP": [
            "~> 4.1"
        "AEXML": [
            "~> 4.2"

Pin It on Pinterest

Share This