---
title: 系统音量调节
permalink: /docs/zh/system-volume.html
key: docs-system-volume
---

`FijkPlayer` 的接口 `setVolume` 提供了调整单个播放器音量的功能，此接口默认音量值是 1.0， 最小是 0.0 （即表示静音），最大根据不同系统可能不同，但设置过大可能出现爆音，需要实际测试。
如果重新创建播放器，那么音量还是会恢复到默认值。
一般在音视频类应用的开发中，可能还涉及到调节系统音量的需求，系统音量调整后值保持不变，除非再次调整。

本节文档描述 fijkplayer 中的系统音量调节接口，以及音量变化的 UI 显示。主要涉及两个类，分别是`FijkVolume` 和 `FijkVolumeWatcher`。

## 调整音量的接口

不同的系统音量最大值和最小值可能不同，在 fijkplayer 中无需关注不同系统的音量最值。  
fijkplayer 将系统的音量范围线性映射到 `[0.0, 1.0]`。
音量可以在 [0.0, 1.0] 之间进行调整，是以一定的间隔进行调整。

通过 FijkVolume 的接口进行音量调整，调整后以接口返回值中的音量为准。因为在部分系统中，音量调节是有最小阶梯值的。

`FijkVolume` 提供调整音量的接口

* `up({double step})` 增大音量，并返回调整之后的音量值
* `down({double step})` 减小音量并返回调整之后的音量值
* `mute()` 静音，并返回调整之后的音量值
* `setVol(double vol)` 设置音量值，并返回调整之后的音量值  
    返回音量值并不一定等于设置的参数，会选择此参数最近的级别进行调整。

## 音量 UI 控制

目前，fijkplayer 中提供了四种不同的 **系统音量UI** 控制模式

1. 当存在 playable 状态的播放器时，隐藏系统的音量变化 UI
2. 当存在 playing 状态（started 状态）的播放器时，隐藏系统的音量变化 UI
3. 从不显示系统音量变化 UI
4. 总是显示系统音量变化 UI

4 种不同的模式分别在 `FijkVolume` 有常量定义。
`hideUIWhenPlayable`、`hideUIWhenPlaying`、`neverShowUI` 和 `alwaysShowUI`。

默认的模式是 `alwaysShowUI`。

通过接口 `FijkVolume.setUIMode(int mode)` 进行模式调整。

## 获取音量变化通知

### FijkVolumeWatcher

`FijkVolumeWatcher` 提供音量变化的通知。`FijkVolumeWatcher` 是一个 Flutter Widget，有三个参数。
```dart
FijkVolumeWatcher({
    @required this.watcher,
    @required this.child,
    bool showToast = false,
})
```

watcher 是音量监听回调函数，定义如下
```
typedef FijkVolumeCallback = void Function(FijkVolumeEvent value);
```

其中 FijkVolumeEvent 定义为：
```dart
class FijkVolumeEvent {
  final double vol;
  final bool sui;
  final int type;
}
```
vol 是音量变化值，范围是 [0.0, 1.0]。 sui 表示此次音量变化事件是否已经有系统UI进行显示。
type 表示音量类型，当前版本都是媒体音量类型。


child 是子 widget，FijkVolumeWatcher 在其 State build 函数中直接返回 child。

showToast 决定在音量变化时是否显示 FijkVolumeWatcher 中默认的音量变化 UI

### Value Listener 接口

FijkVolumeWatcher 本质上就是利用 FijkVolume 中 Value Listener 接口，进行封装，实现的音量监听控件。 

但是如果直接使用 Value Listener 接口，需要注意 addListener 和 removeListener 需要成对出现。

```dart
class FijkVolume {
    static void addListener(VoidCallback listener);
    static void removeListener(VoidCallback listener);
}
```

在注册的回调函数中，通过 `static FijkVolumeEvent get value ` 获取变化之后的系统音量信息。
```dart
void volChanged() {
    FijkVolumeEvent value = FijkVolume.value;
}
```

## Android 额外设置

在 Android 平台监听物理音量按键需要额外的代码调用，并且目前没有找到可行的直接在 fijkplayer 库中进行实现的方式。
所以在 Android 平台如果需要实现监听系统音量调整的功能，还需要进行额外的代码修改。

修改  MainActivity 如下：
```java
public class MainActivity extends FlutterActivity implements FijkVolume.CanListenVolumeKey {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GeneratedPluginRegistrant.registerWith(this);
    }

    private FijkVolume.VolumeKeyListener volumeKeyListener;

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_VOLUME_DOWN:
            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_VOLUME_MUTE:
                if (volumeKeyListener != null)
                    return volumeKeyListener.onVolumeKeyDown(keyCode, event);
        }
        return super.onKeyDown(keyCode, event);
    }


    @Override
    public void setVolumeKeyListener(FijkVolume.VolumeKeyListener listener) {
        volumeKeyListener = listener;
    }
}
```

implements FijkVolume.CanListenVolumeKey 以及对 onKeyDown 的修改是必须的。
