import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiHotplugEvent;
class TvInputHardwareManager implements TvInputHal.Callback {
private static final String TAG = TvInputHardwareManager.class.getSimpleName();
+ private final Context mContext;
private final Listener mListener;
private final TvInputHal mHal = new TvInputHal(this);
private final SparseArray<Connection> mConnections = new SparseArray<>();
private final IHdmiDeviceEventListener mHdmiDeviceEventListener = new HdmiDeviceEventListener();
private final IHdmiSystemAudioModeChangeListener mHdmiSystemAudioModeChangeListener =
new HdmiSystemAudioModeChangeListener();
+ private final BroadcastReceiver mVolumeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ handleVolumeChange(context, intent);
+ }
+ };
+ private int mCurrentIndex = 0;
+ private int mCurrentMaxIndex = 0;
+ private final boolean mUseMasterVolume;
// TODO: Should handle STANDBY case.
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
private final Object mLock = new Object();
public TvInputHardwareManager(Context context, Listener listener) {
+ mContext = context;
mListener = listener;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mUseMasterVolume = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
mHal.init();
}
} else {
Slog.w(TAG, "HdmiControlService is not available");
}
+ if (!mUseMasterVolume) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
+ filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+ mContext.registerReceiver(mVolumeReceiver, filter);
+ }
+ updateVolume();
}
}
}
}
+ private void updateVolume() {
+ mCurrentMaxIndex = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ mCurrentIndex = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ }
+
+ private void handleVolumeChange(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
+ int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+ if (streamType != AudioManager.STREAM_MUSIC) {
+ return;
+ }
+ int index = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0);
+ if (index == mCurrentIndex) {
+ return;
+ }
+ mCurrentIndex = index;
+ } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
+ int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+ if (streamType != AudioManager.STREAM_MUSIC) {
+ return;
+ }
+ // volume index will be updated at onMediaStreamVolumeChanged() through updateVolume().
+ } else {
+ Slog.w(TAG, "Unrecognized intent: " + intent);
+ return;
+ }
+ synchronized (mLock) {
+ for (int i = 0; i < mConnections.size(); ++i) {
+ TvInputHardwareImpl hardwareImpl = mConnections.valueAt(i).getHardwareImplLocked();
+ if (hardwareImpl != null) {
+ hardwareImpl.onMediaStreamVolumeChanged();
+ }
+ }
+ }
+ }
+
+ private float getMediaStreamVolume() {
+ return mUseMasterVolume ? 1.0f : ((float) mCurrentIndex / (float) mCurrentMaxIndex);
+ }
+
private class Connection implements IBinder.DeathRecipient {
private final TvInputHardwareInfo mHardwareInfo;
private TvInputInfo mInfo;
private AudioDevicePort mAudioSink;
private AudioPatch mAudioPatch = null;
private float mCommittedVolume = 0.0f;
- private float mVolume = 0.0f;
+ private float mSourceVolume = 0.0f;
private TvStreamConfig mActiveConfig = null;
return;
}
+ updateVolume();
+ float volume = mSourceVolume * getMediaStreamVolume();
AudioGainConfig sourceGainConfig = null;
- if (mAudioSource.gains().length > 0 && mVolume != mCommittedVolume) {
+ if (mAudioSource.gains().length > 0 && volume != mCommittedVolume) {
AudioGain sourceGain = null;
for (AudioGain gain : mAudioSource.gains()) {
if ((gain.mode() & AudioGain.MODE_JOINT) != 0) {
int steps = (sourceGain.maxValue() - sourceGain.minValue())
/ sourceGain.stepValue();
int gainValue = sourceGain.minValue();
- if (mVolume < 1.0f) {
- gainValue += sourceGain.stepValue() * (int) (mVolume * steps + 0.5);
+ if (volume < 1.0f) {
+ gainValue += sourceGain.stepValue() * (int) (volume * steps + 0.5);
} else {
gainValue = sourceGain.maxValue();
}
- int numChannels = 0;
- for (int mask = sourceGain.channelMask(); mask > 0; mask >>= 1) {
- numChannels += (mask & 1);
- }
- int[] gainValues = new int[numChannels];
- Arrays.fill(gainValues, gainValue);
+ // size of gain values is 1 in MODE_JOINT
+ int[] gainValues = new int[] { gainValue };
sourceGainConfig = sourceGain.buildConfig(AudioGain.MODE_JOINT,
sourceGain.channelMask(), gainValues, 0);
} else {
shouldRecreateAudioPatch = true;
}
if (shouldRecreateAudioPatch) {
- mCommittedVolume = mVolume;
+ mCommittedVolume = volume;
mAudioManager.createAudioPatch(
audioPatchArray,
new AudioPortConfig[] { sourceConfig },
if (mReleased) {
throw new IllegalStateException("Device already released.");
}
- mVolume = volume;
+ mSourceVolume = volume;
updateAudioConfigLocked();
}
}
updateAudioConfigLocked();
}
}
+
+ public void onMediaStreamVolumeChanged() {
+ synchronized (mImplLock) {
+ updateAudioConfigLocked();
+ }
+ }
}
interface Listener {