{"record":{"id":"45fbfdcf3dd24bd4","repo":"google/ExoPlayer","slug":"missing-implementation-to-handle-command-set-devic","errorCode":null,"errorMessage":"Missing implementation to handle COMMAND_SET_DEVICE_VOLUME or COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS","messagePattern":"Missing implementation to handle COMMAND_SET_DEVICE_VOLUME or COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java","lineNumber":3072,"sourceCode":"    throw new IllegalStateException(\"Missing implementation to handle COMMAND_SET_VOLUME\");\n  }\n\n  /**\n   * Handles calls to {@link Player#setDeviceVolume(int)} and {@link Player#setDeviceVolume(int,\n   * int)}.\n   *\n   * <p>Will only be called if {@link Player#COMMAND_SET_DEVICE_VOLUME} or {@link\n   * Player#COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS} is available.\n   *\n   * @param deviceVolume The requested device volume.\n   * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.\n   * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}\n   *     changes caused by this call.\n   */\n  @ForOverride\n  protected ListenableFuture<?> handleSetDeviceVolume(\n      @IntRange(from = 0) int deviceVolume, int flags) {\n    throw new IllegalStateException(\n        \"Missing implementation to handle COMMAND_SET_DEVICE_VOLUME or\"\n            + \" COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS\");\n  }\n\n  /**\n   * Handles calls to {@link Player#increaseDeviceVolume()} and {@link\n   * Player#increaseDeviceVolume(int)}.\n   *\n   * <p>Will only be called if {@link Player#COMMAND_ADJUST_DEVICE_VOLUME} or {@link\n   * Player#COMMAND_ADJUST_DEVICE_VOLUME_WITH_FLAGS} is available.\n   *\n   * @param flags Either 0 or a bitwise combination of one or more {@link C.VolumeFlags}.\n   * @return A {@link ListenableFuture} indicating the completion of all immediate {@link State}\n   *     changes caused by this call.\n   */\n  @ForOverride\n  protected ListenableFuture<?> handleIncreaseDeviceVolume(@C.VolumeFlags int flags) {\n    throw new IllegalStateException(","sourceCodeStart":3054,"sourceCodeEnd":3090,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/common/src/main/java/com/google/android/exoplayer2/SimpleBasePlayer.java#L3054-L3090","documentation":"SimpleBasePlayer routes Player.setDeviceVolume(int) and setDeviceVolume(int, int) to handleSetDeviceVolume(int, int). The default implementation throws IllegalStateException when the subclass declares Player.COMMAND_SET_DEVICE_VOLUME or Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS in availableCommands without overriding the handler. It is a command-advertisement/handler mismatch, not a device failure.","triggerScenarios":"Calling player.setDeviceVolume(...) on a custom SimpleBasePlayer whose State.availableCommands contains COMMAND_SET_DEVICE_VOLUME or COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS while handleSetDeviceVolume is not overridden.","commonSituations":"Reusing a broad command set from an existing player implementation when wrapping a remote or platform player; upgrading Media3 versions where the flags variant was introduced and the command list was widened without adding the handler.","solutions":["Override handleSetDeviceVolume(int deviceVolume, int flags) in the subclass, applying the device volume (e.g. via AudioManager) and returning a completed ListenableFuture.","If device volume cannot be controlled, do not include COMMAND_SET_DEVICE_VOLUME / COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS in availableCommands.","Write a unit test that iterates every advertised command and invokes the corresponding Player method to catch unimplemented handlers early."],"exampleFix":"// before\n// availableCommands includes COMMAND_SET_DEVICE_VOLUME but no override:\n\n// after\n@Override\nprotected ListenableFuture<?> handleSetDeviceVolume(int deviceVolume, int flags) {\n  audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, deviceVolume, flags);\n  return Futures.immediateVoidFuture();\n}","handlingStrategy":"validation","validationCode":"if (player.getState().availableCommands.contains(Player.COMMAND_SET_DEVICE_VOLUME)\n    || player.getState().availableCommands.contains(Player.COMMAND_SET_DEVICE_VOLUME_WITH_FLAGS)) {\n  checkOverrides(playerClass, \"handleSetDeviceVolume\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat device-volume commands as a family: implement set/increase/decrease/mute handlers together or advertise none.","Guard calls: isCommandAvailable(COMMAND_SET_DEVICE_VOLUME) before showing a device-volume UI.","Add a smoke test that invokes each advertised command once against a freshly built player."],"tags":["exoplayer","media3","player","device-volume","subclassing"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}