diff --git a/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilities.java b/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilities.java new file mode 100644 index 0000000000..24bcccaf03 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilities.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.audio; + +import com.google.android.exoplayer.util.Util; + +import android.annotation.TargetApi; +import android.media.AudioFormat; + +import java.util.HashSet; +import java.util.Set; + +/** + * Represents the set of audio formats a device is capable of playing back. + */ +@TargetApi(21) +public final class AudioCapabilities { + + private final Set supportedEncodings; + private final int maxChannelCount; + + /** + * Constructs new audio capabilities based on a set of supported encodings and a maximum channel + * count. + * + * @param supportedEncodings Supported audio encodings from {@link android.media.AudioFormat}'s + * {@code ENCODING_*} constants. + * @param maxChannelCount The maximum number of audio channels that can be played simultaneously. + */ + public AudioCapabilities(int[] supportedEncodings, int maxChannelCount) { + this.supportedEncodings = new HashSet(); + if (supportedEncodings != null) { + for (int i : supportedEncodings) { + this.supportedEncodings.add(i); + } + } + this.maxChannelCount = maxChannelCount; + } + + /** Returns whether the device supports playback of AC-3. */ + public boolean supportsAc3() { + return Util.SDK_INT >= 21 && supportedEncodings.contains(AudioFormat.ENCODING_AC3); + } + + /** Returns whether the device supports playback of enhanced AC-3. */ + public boolean supportsEAc3() { + return Util.SDK_INT >= 21 && supportedEncodings.contains(AudioFormat.ENCODING_E_AC3); + } + + /** Returns whether the device supports playback of 16-bit PCM. */ + public boolean supportsPcm() { + return supportedEncodings.contains(AudioFormat.ENCODING_PCM_16BIT); + } + + /** Returns the maximum number of channels the device can play at the same time. */ + public int getMaxChannelCount() { + return maxChannelCount; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof AudioCapabilities)) { + return false; + } + AudioCapabilities audioCapabilities = (AudioCapabilities) other; + return supportedEncodings.equals(audioCapabilities.supportedEncodings) + && maxChannelCount == audioCapabilities.maxChannelCount; + } + + @Override + public int hashCode() { + return maxChannelCount + 31 * supportedEncodings.hashCode(); + } + + @Override + public String toString() { + return "AudioCapabilities[maxChannelCount=" + maxChannelCount + + ", supportedEncodings=" + supportedEncodings + "]"; + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilitiesReceiver.java b/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilitiesReceiver.java new file mode 100644 index 0000000000..963bb344a8 --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer/audio/AudioCapabilitiesReceiver.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.audio; + +import com.google.android.exoplayer.util.Assertions; +import com.google.android.exoplayer.util.Util; + +import android.annotation.TargetApi; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.media.AudioFormat; +import android.media.AudioManager; + +/** + * Notifies a listener when the audio playback capabilities change. Call {@link #register} to start + * receiving notifications, and {@link #unregister} to stop. + */ +public final class AudioCapabilitiesReceiver { + + /** Listener notified when audio capabilities change. */ + public interface Listener { + + /** Called when the audio capabilities change. */ + void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities); + + } + + /** Default to stereo PCM on SDK <= 21 and when HDMI is unplugged. */ + private static final AudioCapabilities DEFAULT_AUDIO_CAPABILITIES = + new AudioCapabilities(new int[] {AudioFormat.ENCODING_PCM_16BIT}, 2); + + private final Context context; + private final Listener listener; + private final BroadcastReceiver receiver; + + /** + * Constructs a new audio capabilities receiver. + * + * @param context Application context for registering to receive broadcasts. + * @param listener Listener to notify when audio capabilities change. + */ + public AudioCapabilitiesReceiver(Context context, Listener listener) { + this.context = Assertions.checkNotNull(context); + this.listener = Assertions.checkNotNull(listener); + this.receiver = Util.SDK_INT >= 21 ? new HdmiAudioPlugBroadcastReceiver() : null; + } + + /** + * Registers to notify the listener when audio capabilities change. The listener will immediately + * receive the current audio capabilities. It is important to call {@link #unregister} so that + * the listener can be garbage collected. + */ + @TargetApi(21) + public void register() { + if (receiver != null) { + context.registerReceiver(receiver, new IntentFilter(AudioManager.ACTION_HDMI_AUDIO_PLUG)); + } + + listener.onAudioCapabilitiesChanged(DEFAULT_AUDIO_CAPABILITIES); + } + + /** Unregisters to stop notifying the listener when audio capabilities change. */ + public void unregister() { + if (receiver != null) { + context.unregisterReceiver(receiver); + } + } + + @TargetApi(21) + private final class HdmiAudioPlugBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (!action.equals(AudioManager.ACTION_HDMI_AUDIO_PLUG)) { + return; + } + + listener.onAudioCapabilitiesChanged( + new AudioCapabilities(intent.getIntArrayExtra(AudioManager.EXTRA_ENCODINGS), + intent.getIntExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, 0))); + } + + } + +}