Documentation for controlling and preserving Bose SoundTouch devices
This document summarizes the improvements made to the Marge service to improve parity with the upstream Bose SoundTouch service, along with open issues and proposed next steps.
buttonNumber: Correctly mapped the internal ServicePreset.ID or ButtonNumber to the buttonNumber XML attribute in the /full response and ensured it is persisted in the local datastore.<components> (e.g., LIGHTSWITCH, SMSC) and their firmware versions from upstream responses.preferredLanguage to de in the /full response and added synchronization to persist it from upstream responses.providerSettings (e.g., STREAMING_QUALITY, ELIGIBLE_FOR_TRIAL) from the /full response.contentItemType: The contentItemType (e.g., tracklisturl) is now correctly synchronized from upstream, persisted in the local datastore, and returned in the /full response for both presets and recents.token_version_3 type when a token is present in the /full response, improving parity with the upstream service. The service now respects existing credential_type values from Sources.xml (e.g., token_version_3 for Spotify) while providing sensible defaults for new or incomplete sources.Sources.xml to use an attribute-based structure (sourceid, source, status, sourceAccount, etc.) matching the real device’s output. Removed redundant nested tags like <sourcename>, <username>, and <name>.<contentItem> structure within <recent> entries in Recents.xml, maintaining exact parity with the device’s persistence format while supporting legacy flat formats for backward compatibility.serialNumber Casing: Fixed the casing mismatch in the /full response where the upstream uses camelCase <serialNumber> in the top-level <device> and lowercase <serialnumber> in the nested <attachedProduct>. Local responses now correctly mirror this inconsistency.sourceAccount="" is preserved in XML even when empty, matching device behavior for sources like TUNEIN.deviceID and utcTime in Recents.xml.id attributes during “Initial Data Sync”.<name> was empty in some local /full responses by ensuring it is correctly populated from the datastore and synchronized from upstream.<name> tags in the /full response are now self-closing (<name/>), matching upstream behavior.YYMMDD + 3-digit counter) for recent items, ensuring IDs are large, unique, and stay within the 32-bit integer range.POST /recent requests. This improves parity for subsequent GET /recents calls.RADIO_BROWSER provider is included in the public /streaming/sourceproviders list to maintain internal functionality while acknowledging it as a parity gap.AddRecent to correctly extract and echo back base64 tokens/credentials provided in the incoming request, improving source learning.standalone="yes" to the XML declaration for all Marge responses, including recent, presets, full account, software update, and sourceproviders.<sourceSettings/> tags for parity..000+00:00)./streaming/sourceproviders: Root element is <sourceProviders>, but child elements are <sourceprovider> (all lowercase), matching upstream behavior.25 and ensuring sourcename is empty in responses, matching upstream behavior for station playback./streaming/account/{accountId}/full response to match the upstream structure. This includes:
buttonNumber: Correctly mapped the internal ServicePreset.ID to the buttonNumber XML attribute in the /full response.xml.Marshal for the entire response.FullResponseSource, FullResponsePreset, and FullResponseRecent to accurately reflect the upstream structure where <source> is a child element, rather than a set of attributes.<presets> and <recents> correctly nest their associated <source> details, resolving previous data omissions.<serialNumber> and <updatedOn> to both the top-level <device> and its <attachedProduct>, ensuring consistent device identification.<contentItemType> and <productlabel> to match upstream expectations.TestParityMismatchReproduction_V2 and TestParityMismatchReproduction_V3) now confirm parity for identified mismatches in POST /recent and GET /recents, including credentials and source-specific metadata.POST /recent and GET /recents use the same formatting functions, guaranteeing consistency.marge.go by extracting focused helper functions for mapping internal data to response-specific XML models.Based on the latest parity_mismatches and the high-fidelity /full account response comparison (diff14), here are the recommended areas for further work:
Current mismatches in /bmx/tunein/v1/playback/station/... show differences in reporting URLs and missing links:
listen_id=1234567890, while upstream uses a different session-based ID._links or metadata that are currently omitted in local responses.HandleTuneInPlayback logic to better mirror the upstream response structure and parameter generation./full Account Response Data Gaps (Medium)While structural parity for the /full response is high, several value-level gaps remain as shown in diff14:
2024-06-23T07:40:36.000+00:00), whereas some local fields still use Unix epoch integers (e.g., 1234567890).providerSettings block in the local response currently lacks crucial values like keyName, providerId, and boseId (appearing as empty tags).type="") compared to upstream values like LIGHTSWITCH or SMSC.100004) differ from upstream IDs (e.g., 1234567), though this may be expected due to different account/device environments.marge.go and setup.go to ensure all fields in the /full response are correctly populated with high-fidelity values and standard ISO-8601 timestamps.The /oauth/device/.../token endpoint frequently reports mismatches because tokens are naturally different between local and upstream.
access_token field while still verifying that the rest of the JSON structure (expires_in, scope, token_type) matches.While we fixed IDs for recents, other models like presets or sources might still use small auto-incrementing integers.
Continue the “learning” approach for other services. For example, if we see a new sourceproviderid in a Spotify or TuneIn request, we should ensure it is stored and reused.
Analysis of device reboot logs revealed several data requirements:
POST /streaming/support/power_on request. This data is now stored in the local datastore, improving our ability to respond accurately to subsequent management requests.RADIO_BROWSER provider is included in the public /streaming/sourceproviders list to maintain internal functionality while acknowledging it as a parity gap.Structural and value gaps in the /full account response have been addressed:
Key Fixes:
mapRecentsToFullResponse to correctly link recents to their specific ConfiguredSource (e.g., by matching sourceid attribute).