Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
10f142b3
authored
Nov 26, 2019
by
andrewlewis
Committed by
Oliver Woodman
Nov 27, 2019
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Add AudioProcessor.AudioFormat
Issue: #6601 PiperOrigin-RevId: 282515179
parent
b7000e64
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
259 additions
and
329 deletions
extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/BaseAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/ChannelMappingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
library/core/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/TeeAudioProcessor.java
library/core/src/main/java/com/google/android/exoplayer2/audio/TrimmingAudioProcessor.java
library/core/src/test/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessorTest.java
library/core/src/test/java/com/google/android/exoplayer2/audio/SonicAudioProcessorTest.java
extensions/gvr/src/main/java/com/google/android/exoplayer2/ext/gvr/GvrAudioProcessor.java
View file @
10f142b3
...
...
@@ -18,7 +18,6 @@ package com.google.android.exoplayer2.ext.gvr;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.ExoPlayerLibraryInfo
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.audio.AudioProcessor
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.vr.sdk.audio.GvrAudioSurround
;
...
...
@@ -44,8 +43,7 @@ public final class GvrAudioProcessor implements AudioProcessor {
private
static
final
int
OUTPUT_FRAME_SIZE
=
OUTPUT_CHANNEL_COUNT
*
2
;
// 16-bit stereo output.
private
static
final
int
NO_SURROUND_FORMAT
=
GvrAudioSurround
.
SurroundFormat
.
INVALID
;
private
int
sampleRateHz
;
private
int
channelCount
;
private
AudioFormat
inputAudioFormat
;
private
int
pendingGvrAudioSurroundFormat
;
@Nullable
private
GvrAudioSurround
gvrAudioSurround
;
private
ByteBuffer
buffer
;
...
...
@@ -60,8 +58,7 @@ public final class GvrAudioProcessor implements AudioProcessor {
public
GvrAudioProcessor
()
{
// Use the identity for the initial orientation.
w
=
1
f
;
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
inputAudioFormat
=
AudioFormat
.
NOT_SET
;
buffer
=
EMPTY_BUFFER
;
pendingGvrAudioSurroundFormat
=
NO_SURROUND_FORMAT
;
}
...
...
@@ -87,15 +84,13 @@ public final class GvrAudioProcessor implements AudioProcessor {
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
synchronized
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
Encoding
int
encoding
)
throws
UnhandledFormatException
{
if
(
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
public
synchronized
AudioFormat
configure
(
AudioFormat
inputAudioFormat
)
throws
Unhandled
Audio
FormatException
{
if
(
inputAudioFormat
.
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
maybeReleaseGvrAudioSurround
();
throw
new
Unhandled
FormatException
(
sampleRateHz
,
channelCount
,
encoding
);
throw
new
Unhandled
AudioFormatException
(
inputAudioFormat
);
}
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
switch
(
channelCount
)
{
switch
(
inputAudioFormat
.
channelCount
)
{
case
1
:
pendingGvrAudioSurroundFormat
=
GvrAudioSurround
.
SurroundFormat
.
SURROUND_MONO
;
break
;
...
...
@@ -115,12 +110,14 @@ public final class GvrAudioProcessor implements AudioProcessor {
pendingGvrAudioSurroundFormat
=
GvrAudioSurround
.
SurroundFormat
.
THIRD_ORDER_AMBISONICS
;
break
;
default
:
throw
new
Unhandled
FormatException
(
sampleRateHz
,
channelCount
,
encoding
);
throw
new
Unhandled
AudioFormatException
(
inputAudioFormat
);
}
if
(
buffer
==
EMPTY_BUFFER
)
{
buffer
=
ByteBuffer
.
allocateDirect
(
FRAMES_PER_OUTPUT_BUFFER
*
OUTPUT_FRAME_SIZE
)
.
order
(
ByteOrder
.
nativeOrder
());
}
this
.
inputAudioFormat
=
inputAudioFormat
;
return
new
AudioFormat
(
inputAudioFormat
.
sampleRate
,
OUTPUT_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
}
@Override
...
...
@@ -129,21 +126,6 @@ public final class GvrAudioProcessor implements AudioProcessor {
}
@Override
public
int
getOutputChannelCount
()
{
return
OUTPUT_CHANNEL_COUNT
;
}
@Override
public
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_16BIT
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
}
@Override
public
void
queueInput
(
ByteBuffer
input
)
{
int
position
=
input
.
position
();
Assertions
.
checkNotNull
(
gvrAudioSurround
);
...
...
@@ -181,7 +163,10 @@ public final class GvrAudioProcessor implements AudioProcessor {
maybeReleaseGvrAudioSurround
();
gvrAudioSurround
=
new
GvrAudioSurround
(
pendingGvrAudioSurroundFormat
,
sampleRateHz
,
channelCount
,
FRAMES_PER_OUTPUT_BUFFER
);
pendingGvrAudioSurroundFormat
,
inputAudioFormat
.
sampleRate
,
inputAudioFormat
.
channelCount
,
FRAMES_PER_OUTPUT_BUFFER
);
gvrAudioSurround
.
updateNativeOrientation
(
w
,
x
,
y
,
z
);
pendingGvrAudioSurroundFormat
=
NO_SURROUND_FORMAT
;
}
else
if
(
gvrAudioSurround
!=
null
)
{
...
...
@@ -195,8 +180,7 @@ public final class GvrAudioProcessor implements AudioProcessor {
maybeReleaseGvrAudioSurround
();
updateOrientation
(
/* w= */
1
f
,
/* x= */
0
f
,
/* y= */
0
f
,
/* z= */
0
f
);
inputEnded
=
false
;
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
inputAudioFormat
=
AudioFormat
.
NOT_SET
;
buffer
=
EMPTY_BUFFER
;
pendingGvrAudioSurroundFormat
=
NO_SURROUND_FORMAT
;
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioProcessor.java
View file @
10f142b3
...
...
@@ -16,6 +16,8 @@
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Util
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
...
...
@@ -23,24 +25,56 @@ import java.nio.ByteOrder;
* Interface for audio processors, which take audio data as input and transform it, potentially
* modifying its channel count, encoding and/or sample rate.
*
* <p>Call {@link #configure(int, int, int)} to configure the processor to receive input audio, then
* call {@link #isActive()} to determine whether the processor is active in the new configuration.
* {@link #queueInput(ByteBuffer)}, {@link #getOutputChannelCount()}, {@link #getOutputEncoding()}
* and {@link #getOutputSampleRateHz()} may only be called if the processor is active. Call {@link
* #reset()} to reset the processor to its unconfigured state and release any resources.
*
* <p>In addition to being able to modify the format of audio, implementations may allow parameters
* to be set that affect the output audio and whether the processor is active/inactive.
*/
public
interface
AudioProcessor
{
/** PCM audio format that may be handled by an audio processor. */
final
class
AudioFormat
{
public
static
final
AudioFormat
NOT_SET
=
new
AudioFormat
(
/* sampleRate= */
Format
.
NO_VALUE
,
/* channelCount= */
Format
.
NO_VALUE
,
/* encoding= */
Format
.
NO_VALUE
);
/** The sample rate in Hertz. */
public
final
int
sampleRate
;
/** The number of interleaved channels. */
public
final
int
channelCount
;
/** The type of linear PCM encoding. */
@C
.
PcmEncoding
public
final
int
encoding
;
/** The number of bytes used to represent one audio frame. */
public
final
int
bytesPerFrame
;
public
AudioFormat
(
int
sampleRate
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
this
.
sampleRate
=
sampleRate
;
this
.
channelCount
=
channelCount
;
this
.
encoding
=
encoding
;
bytesPerFrame
=
Util
.
isEncodingLinearPcm
(
encoding
)
?
Util
.
getPcmFrameSize
(
encoding
,
channelCount
)
:
Format
.
NO_VALUE
;
}
@Override
public
String
toString
()
{
return
"AudioFormat["
+
"sampleRate="
+
sampleRate
+
", channelCount="
+
channelCount
+
", encoding="
+
encoding
+
']'
;
}
}
/** Exception thrown when a processor can't be configured for a given input audio format. */
final
class
UnhandledFormatException
extends
Exception
{
final
class
Unhandled
Audio
FormatException
extends
Exception
{
public
UnhandledFormatException
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
super
(
"Unhandled format: "
+
sampleRateHz
+
" Hz, "
+
channelCount
+
" channels in encoding "
+
encoding
);
public
UnhandledAudioFormatException
(
AudioFormat
inputAudioFormat
)
{
super
(
"Unhandled format: "
+
inputAudioFormat
);
}
}
...
...
@@ -50,46 +84,24 @@ public interface AudioProcessor {
/**
* Configures the processor to process input audio with the specified format. After calling this
* method, call {@link #isActive()} to determine whether the audio processor is active.
*
* <p>If the audio processor is active after configuration, call {@link #getOutputSampleRateHz()},
* {@link #getOutputChannelCount()} and {@link #getOutputEncoding()} to get its new output format.
* method, call {@link #isActive()} to determine whether the audio processor is active. Returns
* the configured output audio format if this instance is active.
*
* <p>After calling this method, it is necessary to {@link #flush()} the processor to apply the
* new configuration before queueing more data. You can (optionally) first drain output in the
* previous configuration by calling {@link #queueEndOfStream()} and {@link #getOutput()}.
*
* @param
sampleRateHz The sample rate of input audio in Hz.
*
@param channelCount The number of interleaved channels in input audio
.
* @
param encoding The encoding of input audio
.
* @throws UnhandledFormatException Thrown if the specified format can't be handled as input.
* @param
inputAudioFormat The format of audio that will be queued after the next call to {@link
*
#flush()}
.
* @
return The configured output audio format if this instance is {@link #isActive() active}
.
* @throws Unhandled
Audio
FormatException Thrown if the specified format can't be handled as input.
*/
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
throws
UnhandledFormatException
;
AudioFormat
configure
(
AudioFormat
inputAudioFormat
)
throws
UnhandledAudioFormatException
;
/** Returns whether the processor is configured and will process input buffers. */
boolean
isActive
();
/**
* Returns the number of audio channels in the data output by the processor. The value may change
* as a result of calling {@link #configure(int, int, int)}.
*/
int
getOutputChannelCount
();
/**
* Returns the audio encoding used in the data output by the processor. The value may change as a
* result of calling {@link #configure(int, int, int)}.
*/
@C
.
PcmEncoding
int
getOutputEncoding
();
/**
* Returns the sample rate of audio output by the processor, in hertz. The value may change as a
* result of calling {@link #configure(int, int, int)}.
*/
int
getOutputSampleRateHz
();
/**
* Queues audio data between the position and limit of the input {@code buffer} for processing.
* {@code buffer} must be a direct byte buffer with native byte order. Its contents are treated as
* read-only. Its position will be advanced by the number of bytes consumed (which may be zero).
...
...
@@ -130,6 +142,6 @@ public interface AudioProcessor {
*/
void
flush
();
/** Resets the processor to its unconfigured state. */
/** Resets the processor to its unconfigured state
, releasing any resources
. */
void
reset
();
}
library/core/src/main/java/com/google/android/exoplayer2/audio/BaseAudioProcessor.java
View file @
10f142b3
...
...
@@ -16,24 +16,20 @@
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
androidx.annotation.CallSuper
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
/**
* Base class for audio processors that keep an output buffer and an internal buffer that is reused
* whenever input is queued.
* whenever input is queued. Subclasses should override {@link #onConfigure(AudioFormat)} to return
* the output audio format for the processor if it's active.
*/
public
abstract
class
BaseAudioProcessor
implements
AudioProcessor
{
/** The configured input sample rate, in Hertz, or {@link Format#NO_VALUE} if not configured. */
protected
int
sampleRateHz
;
/** The configured input channel count, or {@link Format#NO_VALUE} if not configured. */
protected
int
channelCount
;
/** The configured input encoding, or {@link Format#NO_VALUE} if not configured. */
@C
.
PcmEncoding
protected
int
encoding
;
/** The configured input audio format. */
protected
AudioFormat
inputAudioFormat
;
private
AudioFormat
outputAudioFormat
;
private
ByteBuffer
buffer
;
private
ByteBuffer
outputBuffer
;
private
boolean
inputEnded
;
...
...
@@ -41,29 +37,21 @@ public abstract class BaseAudioProcessor implements AudioProcessor {
public
BaseAudioProcessor
()
{
buffer
=
EMPTY_BUFFER
;
outputBuffer
=
EMPTY_BUFFER
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
encoding
=
Format
.
NO_VALUE
;
inputAudioFormat
=
AudioFormat
.
NOT_SET
;
outputAudioFormat
=
AudioFormat
.
NOT_SET
;
}
@Override
public
boolean
isActive
()
{
return
sampleRateHz
!=
Format
.
NO_VALUE
;
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
}
@Override
public
int
getOutputEncoding
()
{
return
encoding
;
public
final
AudioFormat
configure
(
AudioFormat
inputAudioFormat
)
throws
UnhandledAudioFormatException
{
this
.
inputAudioFormat
=
inputAudioFormat
;
outputAudioFormat
=
onConfigure
(
inputAudioFormat
);
return
isActive
()
?
outputAudioFormat
:
AudioFormat
.
NOT_SET
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
sampleRateHz
;
public
boolean
isActive
()
{
return
outputAudioFormat
!=
AudioFormat
.
NOT_SET
;
}
@Override
...
...
@@ -98,20 +86,11 @@ public abstract class BaseAudioProcessor implements AudioProcessor {
public
final
void
reset
()
{
flush
();
buffer
=
EMPTY_BUFFER
;
sampleRateHz
=
Format
.
NO_VALUE
;
channelCount
=
Format
.
NO_VALUE
;
encoding
=
Format
.
NO_VALUE
;
inputAudioFormat
=
AudioFormat
.
NOT_SET
;
outputAudioFormat
=
AudioFormat
.
NOT_SET
;
onReset
();
}
/** Sets the input format of this processor. */
protected
final
void
setInputFormat
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
this
.
encoding
=
encoding
;
}
/**
* Replaces the current output buffer with a buffer of at least {@code count} bytes and returns
* it. Callers should write to the returned buffer then {@link ByteBuffer#flip()} it so it can be
...
...
@@ -132,6 +111,12 @@ public abstract class BaseAudioProcessor implements AudioProcessor {
return
outputBuffer
.
hasRemaining
();
}
/** Called when the processor is configured for a new input format. */
protected
AudioFormat
onConfigure
(
AudioFormat
inputAudioFormat
)
throws
UnhandledAudioFormatException
{
return
AudioFormat
.
NOT_SET
;
}
/** Called when the end-of-stream is queued to the processor. */
protected
void
onQueueEndOfStream
()
{
// Do nothing.
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/ChannelMappingAudioProcessor.java
View file @
10f142b3
...
...
@@ -24,19 +24,17 @@ import java.nio.ByteBuffer;
* An {@link AudioProcessor} that applies a mapping from input channels onto specified output
* channels. This can be used to reorder, duplicate or discard channels.
*/
/* package */
// the constructor does not initialize fields: pendingOutputChannels, outputChannels
@SuppressWarnings
(
"nullness:initialization.fields.uninitialized"
)
final
class
ChannelMappingAudioProcessor
extends
BaseAudioProcessor
{
/* package */
final
class
ChannelMappingAudioProcessor
extends
BaseAudioProcessor
{
@Nullable
private
int
[]
pendingOutputChannels
;
private
boolean
active
;
@Nullable
private
int
[]
outputChannels
;
/**
* Resets the channel mapping. After calling this method, call {@link #configure(
int, int, int)}
*
to
start using the new channel map.
* Resets the channel mapping. After calling this method, call {@link #configure(
AudioFormat)} to
* start using the new channel map.
*
* @param outputChannels The mapping from input to output channel indices, or {@code null} to
* leave the input unchanged.
...
...
@@ -47,38 +45,30 @@ final class ChannelMappingAudioProcessor extends BaseAudioProcessor {
}
@Override
public
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
throws
UnhandledFormatException
{
public
AudioFormat
onConfigure
(
AudioFormat
inputAudioFormat
)
throws
Unhandled
Audio
FormatException
{
outputChannels
=
pendingOutputChannels
;
int
[]
outputChannels
=
this
.
outputChannels
;
if
(
outputChannels
==
null
)
{
active
=
false
;
return
;
return
AudioFormat
.
NOT_SET
;
}
if
(
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
if
(
inputAudioFormat
.
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
UnhandledAudioFormatException
(
inputAudioFormat
);
}
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
active
=
channelCount
!=
outputChannels
.
length
;
boolean
active
=
inputAudioFormat
.
channelCount
!=
outputChannels
.
length
;
for
(
int
i
=
0
;
i
<
outputChannels
.
length
;
i
++)
{
int
channelIndex
=
outputChannels
[
i
];
if
(
channelIndex
>=
channelCount
)
{
throw
new
Unhandled
FormatException
(
sampleRateHz
,
channelCount
,
encoding
);
if
(
channelIndex
>=
inputAudioFormat
.
channelCount
)
{
throw
new
Unhandled
AudioFormatException
(
inputAudioFormat
);
}
active
|=
(
channelIndex
!=
i
);
}
}
@Override
public
boolean
isActive
()
{
return
active
;
}
@Override
public
int
getOutputChannelCount
()
{
return
outputChannels
==
null
?
channelCount
:
outputChannels
.
length
;
return
active
?
new
AudioFormat
(
inputAudioFormat
.
sampleRate
,
outputChannels
.
length
,
C
.
ENCODING_PCM_16BIT
)
:
AudioFormat
.
NOT_SET
;
}
@Override
...
...
@@ -86,14 +76,14 @@ final class ChannelMappingAudioProcessor extends BaseAudioProcessor {
int
[]
outputChannels
=
Assertions
.
checkNotNull
(
this
.
outputChannels
);
int
position
=
inputBuffer
.
position
();
int
limit
=
inputBuffer
.
limit
();
int
frameCount
=
(
limit
-
position
)
/
(
2
*
channelCount
);
int
frameCount
=
(
limit
-
position
)
/
(
2
*
inputAudioFormat
.
channelCount
);
int
outputSize
=
frameCount
*
outputChannels
.
length
*
2
;
ByteBuffer
buffer
=
replaceOutputBuffer
(
outputSize
);
while
(
position
<
limit
)
{
for
(
int
channelIndex
:
outputChannels
)
{
buffer
.
putShort
(
inputBuffer
.
getShort
(
position
+
2
*
channelIndex
));
}
position
+=
channelCount
*
2
;
position
+=
inputAudioFormat
.
channelCount
*
2
;
}
inputBuffer
.
position
(
limit
);
buffer
.
flip
();
...
...
@@ -103,7 +93,6 @@ final class ChannelMappingAudioProcessor extends BaseAudioProcessor {
protected
void
onReset
()
{
outputChannels
=
null
;
pendingOutputChannels
=
null
;
active
=
false
;
}
}
library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
View file @
10f142b3
...
...
@@ -27,6 +27,7 @@ import androidx.annotation.Nullable;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.PlaybackParameters
;
import
com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Util
;
...
...
@@ -435,18 +436,22 @@ public final class DefaultAudioSink implements AudioSink {
if
(
processingEnabled
)
{
trimmingAudioProcessor
.
setTrimFrameCount
(
trimStartFrames
,
trimEndFrames
);
channelMappingAudioProcessor
.
setChannelMap
(
outputChannels
);
AudioProcessor
.
AudioFormat
inputAudioFormat
=
new
AudioProcessor
.
AudioFormat
(
sampleRate
,
channelCount
,
encoding
);
AudioProcessor
.
AudioFormat
outputAudioFormat
=
inputAudioFormat
;
for
(
AudioProcessor
audioProcessor
:
availableAudioProcessors
)
{
try
{
audioProcessor
.
configure
(
sampleRate
,
channelCount
,
encoding
);
}
catch
(
AudioProcessor
.
Unhandled
FormatException
e
)
{
outputAudioFormat
=
audioProcessor
.
configure
(
inputAudioFormat
);
}
catch
(
UnhandledAudio
FormatException
e
)
{
throw
new
ConfigurationException
(
e
);
}
if
(
audioProcessor
.
isActive
())
{
channelCount
=
audioProcessor
.
getOutputChannelCount
();
sampleRate
=
audioProcessor
.
getOutputSampleRateHz
();
encoding
=
audioProcessor
.
getOutputEncoding
();
inputAudioFormat
=
outputAudioFormat
;
}
}
sampleRate
=
outputAudioFormat
.
sampleRate
;
channelCount
=
outputAudioFormat
.
channelCount
;
encoding
=
outputAudioFormat
.
encoding
;
}
int
outputChannelConfig
=
getChannelConfig
(
channelCount
,
isInputPcm
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/FloatResamplingAudioProcessor.java
View file @
10f142b3
...
...
@@ -16,6 +16,7 @@
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Util
;
import
java.nio.ByteBuffer
;
...
...
@@ -29,27 +30,21 @@ import java.nio.ByteBuffer;
private
static
final
double
PCM_32_BIT_INT_TO_PCM_32_BIT_FLOAT_FACTOR
=
1.0
/
0x7FFFFFFF
;
@Override
public
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
throws
UnhandledFormatException
{
if
(!
Util
.
isEncodingHighResolutionIntegerPcm
(
encoding
))
{
throw
new
Unhandled
FormatException
(
sampleRateHz
,
channelCount
,
encoding
);
public
AudioFormat
onConfigure
(
AudioFormat
inputAudioFormat
)
throws
Unhandled
Audio
FormatException
{
if
(!
Util
.
isEncodingHighResolutionIntegerPcm
(
inputAudioFormat
.
encoding
))
{
throw
new
Unhandled
AudioFormatException
(
inputAudioFormat
);
}
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
}
@Override
public
boolean
isActive
()
{
return
Util
.
isEncodingHighResolutionIntegerPcm
(
encoding
);
}
@Override
public
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_FLOAT
;
return
Util
.
isEncodingHighResolutionIntegerPcm
(
inputAudioFormat
.
encoding
)
?
new
AudioFormat
(
inputAudioFormat
.
sampleRate
,
inputAudioFormat
.
channelCount
,
C
.
ENCODING_PCM_FLOAT
)
:
AudioFormat
.
NOT_SET
;
}
@Override
public
void
queueInput
(
ByteBuffer
inputBuffer
)
{
boolean
isInput32Bit
=
encoding
==
C
.
ENCODING_PCM_32BIT
;
Assertions
.
checkState
(
Util
.
isEncodingHighResolutionIntegerPcm
(
inputAudioFormat
.
encoding
));
boolean
isInput32Bit
=
inputAudioFormat
.
encoding
==
C
.
ENCODING_PCM_32BIT
;
int
position
=
inputBuffer
.
position
();
int
limit
=
inputBuffer
.
limit
();
int
size
=
limit
-
position
;
...
...
@@ -65,7 +60,7 @@ import java.nio.ByteBuffer;
|
((
inputBuffer
.
get
(
i
+
3
)
&
0xFF
)
<<
24
);
writePcm32BitFloat
(
pcm32BitInteger
,
buffer
);
}
}
else
{
}
else
{
// Input is 24-bit PCM.
for
(
int
i
=
position
;
i
<
limit
;
i
+=
3
)
{
int
pcm32BitInteger
=
((
inputBuffer
.
get
(
i
)
&
0xFF
)
<<
8
)
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/ResamplingAudioProcessor.java
View file @
10f142b3
...
...
@@ -26,23 +26,17 @@ import java.nio.ByteBuffer;
/* package */
final
class
ResamplingAudioProcessor
extends
BaseAudioProcessor
{
@Override
public
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
throws
UnhandledFormatException
{
public
AudioFormat
onConfigure
(
AudioFormat
inputAudioFormat
)
throws
UnhandledAudioFormatException
{
@C
.
PcmEncoding
int
encoding
=
inputAudioFormat
.
encoding
;
if
(
encoding
!=
C
.
ENCODING_PCM_8BIT
&&
encoding
!=
C
.
ENCODING_PCM_16BIT
&&
encoding
!=
C
.
ENCODING_PCM_24BIT
&&
encoding
!=
C
.
ENCODING_PCM_32BIT
)
{
throw
new
Unhandled
FormatException
(
sampleRateHz
,
channelCount
,
encoding
);
throw
new
Unhandled
AudioFormatException
(
inputAudioFormat
);
}
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
}
@Override
public
boolean
isActive
()
{
return
encoding
!=
C
.
ENCODING_INVALID
&&
encoding
!=
C
.
ENCODING_PCM_16BIT
;
}
@Override
public
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_16BIT
;
return
encoding
!=
C
.
ENCODING_PCM_16BIT
?
new
AudioFormat
(
inputAudioFormat
.
sampleRate
,
inputAudioFormat
.
channelCount
,
C
.
ENCODING_PCM_16BIT
)
:
AudioFormat
.
NOT_SET
;
}
@Override
...
...
@@ -52,7 +46,7 @@ import java.nio.ByteBuffer;
int
limit
=
inputBuffer
.
limit
();
int
size
=
limit
-
position
;
int
resampledSize
;
switch
(
encoding
)
{
switch
(
inputAudioFormat
.
encoding
)
{
case
C
.
ENCODING_PCM_8BIT
:
resampledSize
=
size
*
2
;
break
;
...
...
@@ -74,7 +68,7 @@ import java.nio.ByteBuffer;
// Resample the little endian input and update the input/output buffers.
ByteBuffer
buffer
=
replaceOutputBuffer
(
resampledSize
);
switch
(
encoding
)
{
switch
(
inputAudioFormat
.
encoding
)
{
case
C
.
ENCODING_PCM_8BIT
:
// 8->16 bit resampling. Shift each byte from [0, 256) to [-128, 128) and scale up.
for
(
int
i
=
position
;
i
<
limit
;
i
++)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessor.java
View file @
10f142b3
...
...
@@ -119,18 +119,17 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
// AudioProcessor implementation.
@Override
public
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
throws
UnhandledFormatException
{
if
(
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
Unhandled
FormatException
(
sampleRateHz
,
channelCount
,
encoding
);
public
AudioFormat
onConfigure
(
AudioFormat
inputAudioFormat
)
throws
Unhandled
Audio
FormatException
{
if
(
inputAudioFormat
.
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
Unhandled
AudioFormatException
(
inputAudioFormat
);
}
bytesPerFrame
=
channelCount
*
2
;
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
return
enabled
?
inputAudioFormat
:
AudioFormat
.
NOT_SET
;
}
@Override
public
boolean
isActive
()
{
return
super
.
isActive
()
&&
enabled
;
return
enabled
;
}
@Override
...
...
@@ -165,7 +164,8 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
@Override
protected
void
onFlush
()
{
if
(
isActive
())
{
if
(
enabled
)
{
bytesPerFrame
=
inputAudioFormat
.
bytesPerFrame
;
int
maybeSilenceBufferSize
=
durationUsToFrames
(
MINIMUM_SILENCE_DURATION_US
)
*
bytesPerFrame
;
if
(
maybeSilenceBuffer
.
length
!=
maybeSilenceBufferSize
)
{
maybeSilenceBuffer
=
new
byte
[
maybeSilenceBufferSize
];
...
...
@@ -317,7 +317,7 @@ public final class SilenceSkippingAudioProcessor extends BaseAudioProcessor {
* Returns the number of input frames corresponding to {@code durationUs} microseconds of audio.
*/
private
int
durationUsToFrames
(
long
durationUs
)
{
return
(
int
)
((
durationUs
*
sampleRateHz
)
/
C
.
MICROS_PER_SECOND
);
return
(
int
)
((
durationUs
*
inputAudioFormat
.
sampleRate
)
/
C
.
MICROS_PER_SECOND
);
}
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/SonicAudioProcessor.java
View file @
10f142b3
...
...
@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.audio;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C.Encoding
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Util
;
...
...
@@ -62,12 +61,12 @@ public final class SonicAudioProcessor implements AudioProcessor {
*/
private
static
final
int
MIN_BYTES_FOR_SPEEDUP_CALCULATION
=
1024
;
private
int
channelCount
;
private
int
sampleRateHz
;
private
int
pendingOutputSampleRate
;
private
float
speed
;
private
float
pitch
;
private
int
outputSampleRateHz
;
private
int
pendingOutputSampleRateHz
;
private
AudioFormat
inputAudioFormat
;
private
AudioFormat
outputAudioFormat
;
private
boolean
pendingSonicRecreation
;
@Nullable
private
Sonic
sonic
;
...
...
@@ -84,13 +83,12 @@ public final class SonicAudioProcessor implements AudioProcessor {
public
SonicAudioProcessor
()
{
speed
=
1
f
;
pitch
=
1
f
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
outputSampleRateHz
=
Format
.
NO_VALUE
;
inputAudioFormat
=
AudioFormat
.
NOT_SET
;
outputAudioFormat
=
AudioFormat
.
NOT_SET
;
buffer
=
EMPTY_BUFFER
;
shortBuffer
=
buffer
.
asShortBuffer
();
outputBuffer
=
EMPTY_BUFFER
;
pendingOutputSampleRate
Hz
=
SAMPLE_RATE_NO_CHANGE
;
pendingOutputSampleRate
=
SAMPLE_RATE_NO_CHANGE
;
}
/**
...
...
@@ -129,14 +127,14 @@ public final class SonicAudioProcessor implements AudioProcessor {
/**
* Sets the sample rate for output audio, in hertz. Pass {@link #SAMPLE_RATE_NO_CHANGE} to output
* audio at the same sample rate as the input. After calling this method, call
*
{@link #configure(int, int, in
t)} to start using the new sample rate.
* audio at the same sample rate as the input. After calling this method, call
{@link
*
#configure(AudioForma
t)} to start using the new sample rate.
*
* @param sampleRateHz The sample rate for output audio, in hertz.
* @see #configure(
int, int, in
t)
* @see #configure(
AudioForma
t)
*/
public
void
setOutputSampleRateHz
(
int
sampleRateHz
)
{
pendingOutputSampleRate
Hz
=
sampleRateHz
;
pendingOutputSampleRate
=
sampleRateHz
;
}
/**
...
...
@@ -149,50 +147,39 @@ public final class SonicAudioProcessor implements AudioProcessor {
*/
public
long
scaleDurationForSpeedup
(
long
duration
)
{
if
(
outputBytes
>=
MIN_BYTES_FOR_SPEEDUP_CALCULATION
)
{
return
output
SampleRateHz
==
sampleRateHz
return
output
AudioFormat
.
sampleRate
==
inputAudioFormat
.
sampleRate
?
Util
.
scaleLargeTimestamp
(
duration
,
inputBytes
,
outputBytes
)
:
Util
.
scaleLargeTimestamp
(
duration
,
inputBytes
*
outputSampleRateHz
,
outputBytes
*
sampleRateHz
);
:
Util
.
scaleLargeTimestamp
(
duration
,
inputBytes
*
outputAudioFormat
.
sampleRate
,
outputBytes
*
inputAudioFormat
.
sampleRate
);
}
else
{
return
(
long
)
((
double
)
speed
*
duration
);
}
}
@Override
public
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@Encoding
int
encoding
)
throws
UnhandledFormatException
{
if
(
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
UnhandledFormatException
(
sampleRateHz
,
channelCount
,
encoding
);
public
AudioFormat
configure
(
AudioFormat
inputAudioFormat
)
throws
UnhandledAudioFormatException
{
if
(
inputAudioFormat
.
encoding
!=
C
.
ENCODING_PCM_16BIT
)
{
throw
new
UnhandledAudioFormatException
(
inputAudioFormat
);
}
int
outputSampleRateHz
=
pendingOutputSampleRateHz
==
SAMPLE_RATE_NO_CHANGE
?
sampleRateHz
:
pendingOutputSampleRateHz
;
this
.
sampleRateHz
=
sampleRateHz
;
this
.
channelCount
=
channelCount
;
this
.
outputSampleRateHz
=
outputSampleRateHz
;
int
outputSampleRateHz
=
pendingOutputSampleRate
==
SAMPLE_RATE_NO_CHANGE
?
inputAudioFormat
.
sampleRate
:
pendingOutputSampleRate
;
this
.
inputAudioFormat
=
inputAudioFormat
;
this
.
outputAudioFormat
=
new
AudioFormat
(
outputSampleRateHz
,
inputAudioFormat
.
channelCount
,
C
.
ENCODING_PCM_16BIT
);
pendingSonicRecreation
=
true
;
return
outputAudioFormat
;
}
@Override
public
boolean
isActive
()
{
return
sampleRateHz
!=
Format
.
NO_VALUE
return
outputAudioFormat
.
sampleRate
!=
Format
.
NO_VALUE
&&
(
Math
.
abs
(
speed
-
1
f
)
>=
CLOSE_THRESHOLD
||
Math
.
abs
(
pitch
-
1
f
)
>=
CLOSE_THRESHOLD
||
outputSampleRateHz
!=
sampleRateHz
);
}
@Override
public
int
getOutputChannelCount
()
{
return
channelCount
;
}
@Override
public
int
getOutputEncoding
()
{
return
C
.
ENCODING_PCM_16BIT
;
}
@Override
public
int
getOutputSampleRateHz
()
{
return
outputSampleRateHz
;
||
outputAudioFormat
.
sampleRate
!=
inputAudioFormat
.
sampleRate
);
}
@Override
...
...
@@ -245,7 +232,13 @@ public final class SonicAudioProcessor implements AudioProcessor {
public
void
flush
()
{
if
(
isActive
())
{
if
(
pendingSonicRecreation
)
{
sonic
=
new
Sonic
(
sampleRateHz
,
channelCount
,
speed
,
pitch
,
outputSampleRateHz
);
sonic
=
new
Sonic
(
inputAudioFormat
.
sampleRate
,
inputAudioFormat
.
channelCount
,
speed
,
pitch
,
outputAudioFormat
.
sampleRate
);
}
else
if
(
sonic
!=
null
)
{
sonic
.
flush
();
}
...
...
@@ -260,13 +253,12 @@ public final class SonicAudioProcessor implements AudioProcessor {
public
void
reset
()
{
speed
=
1
f
;
pitch
=
1
f
;
channelCount
=
Format
.
NO_VALUE
;
sampleRateHz
=
Format
.
NO_VALUE
;
outputSampleRateHz
=
Format
.
NO_VALUE
;
inputAudioFormat
=
AudioFormat
.
NOT_SET
;
outputAudioFormat
=
AudioFormat
.
NOT_SET
;
buffer
=
EMPTY_BUFFER
;
shortBuffer
=
buffer
.
asShortBuffer
();
outputBuffer
=
EMPTY_BUFFER
;
pendingOutputSampleRate
Hz
=
SAMPLE_RATE_NO_CHANGE
;
pendingOutputSampleRate
=
SAMPLE_RATE_NO_CHANGE
;
pendingSonicRecreation
=
false
;
sonic
=
null
;
inputBytes
=
0
;
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/TeeAudioProcessor.java
View file @
10f142b3
...
...
@@ -64,8 +64,9 @@ public final class TeeAudioProcessor extends BaseAudioProcessor {
}
@Override
public
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
{
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
public
AudioFormat
onConfigure
(
AudioFormat
inputAudioFormat
)
{
// This processor is always active (if passed to the sink) and outputs its input.
return
inputAudioFormat
;
}
@Override
...
...
@@ -81,7 +82,8 @@ public final class TeeAudioProcessor extends BaseAudioProcessor {
@Override
protected
void
onFlush
()
{
if
(
isActive
())
{
audioBufferSink
.
flush
(
sampleRateHz
,
channelCount
,
encoding
);
audioBufferSink
.
flush
(
inputAudioFormat
.
sampleRate
,
inputAudioFormat
.
channelCount
,
inputAudioFormat
.
encoding
);
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/TrimmingAudioProcessor.java
View file @
10f142b3
...
...
@@ -24,7 +24,6 @@ import java.nio.ByteBuffer;
@C
.
PcmEncoding
private
static
final
int
OUTPUT_ENCODING
=
C
.
ENCODING_PCM_16BIT
;
private
boolean
isActive
;
private
int
trimStartFrames
;
private
int
trimEndFrames
;
private
int
bytesPerFrame
;
...
...
@@ -42,7 +41,7 @@ import java.nio.ByteBuffer;
/**
* Sets the number of audio frames to trim from the start and end of audio passed to this
* processor. After calling this method, call {@link #configure(
int, int, in
t)} to apply the new
* processor. After calling this method, call {@link #configure(
AudioForma
t)} to apply the new
* trimming frame counts.
*
* @param trimStartFrames The number of audio frames to trim from the start of audio.
...
...
@@ -68,26 +67,20 @@ import java.nio.ByteBuffer;
}
@Override
public
void
configure
(
int
sampleRateHz
,
int
channelCount
,
@C
.
PcmEncoding
int
encoding
)
throws
UnhandledFormatException
{
if
(
encoding
!=
OUTPUT_ENCODING
)
{
throw
new
Unhandled
FormatException
(
sampleRateHz
,
channelCount
,
encoding
);
public
AudioFormat
onConfigure
(
AudioFormat
inputAudioFormat
)
throws
Unhandled
Audio
FormatException
{
if
(
inputAudioFormat
.
encoding
!=
OUTPUT_ENCODING
)
{
throw
new
Unhandled
AudioFormatException
(
inputAudioFormat
);
}
if
(
endBufferSize
>
0
)
{
trimmedFrameCount
+=
endBufferSize
/
bytesPerFrame
;
}
bytesPerFrame
=
Util
.
getPcmFrameSize
(
OUTPUT_ENCODING
,
channelCount
)
;
bytesPerFrame
=
inputAudioFormat
.
bytesPerFrame
;
endBuffer
=
new
byte
[
trimEndFrames
*
bytesPerFrame
];
endBufferSize
=
0
;
pendingTrimStartBytes
=
trimStartFrames
*
bytesPerFrame
;
isActive
=
trimStartFrames
!=
0
||
trimEndFrames
!=
0
;
receivedInputSinceConfigure
=
false
;
setInputFormat
(
sampleRateHz
,
channelCount
,
encoding
);
}
@Override
public
boolean
isActive
()
{
return
isActive
;
return
trimStartFrames
!=
0
||
trimEndFrames
!=
0
?
inputAudioFormat
:
AudioFormat
.
NOT_SET
;
}
@Override
...
...
@@ -140,7 +133,6 @@ import java.nio.ByteBuffer;
buffer
.
flip
();
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
ByteBuffer
getOutput
()
{
if
(
super
.
isEnded
()
&&
endBufferSize
>
0
)
{
...
...
@@ -155,7 +147,6 @@ import java.nio.ByteBuffer;
return
super
.
getOutput
();
}
@SuppressWarnings
(
"ReferenceEquality"
)
@Override
public
boolean
isEnded
()
{
return
super
.
isEnded
()
&&
endBufferSize
==
0
;
...
...
library/core/src/test/java/com/google/android/exoplayer2/audio/SilenceSkippingAudioProcessorTest.java
View file @
10f142b3
...
...
@@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat
;
import
com.google.android.exoplayer2.util.Assertions
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
...
...
@@ -31,8 +32,9 @@ import org.junit.runner.RunWith;
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
SilenceSkippingAudioProcessorTest
{
private
static
final
int
TEST_SIGNAL_SAMPLE_RATE_HZ
=
1000
;
private
static
final
int
TEST_SIGNAL_CHANNEL_COUNT
=
2
;
private
static
final
AudioFormat
AUDIO_FORMAT
=
new
AudioFormat
(
/* sampleRate= */
1000
,
/* channelCount= */
2
,
/* encoding= */
C
.
ENCODING_PCM_16BIT
);
private
static
final
int
TEST_SIGNAL_SILENCE_DURATION_MS
=
1000
;
private
static
final
int
TEST_SIGNAL_NOISE_DURATION_MS
=
1000
;
private
static
final
int
TEST_SIGNAL_FRAME_COUNT
=
100000
;
...
...
@@ -52,8 +54,7 @@ public final class SilenceSkippingAudioProcessorTest {
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
// When configuring it.
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
// It's active.
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
...
...
@@ -65,8 +66,7 @@ public final class SilenceSkippingAudioProcessorTest {
silenceSkippingAudioProcessor
.
setEnabled
(
false
);
// When configuring it.
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
// It's not active.
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isFalse
();
...
...
@@ -76,8 +76,7 @@ public final class SilenceSkippingAudioProcessorTest {
public
void
testDefaultProcessor_isNotEnabled
()
throws
Exception
{
// Given a processor in its default state.
// When reconfigured.
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
// It's not active.
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isFalse
();
...
...
@@ -88,16 +87,13 @@ public final class SilenceSkippingAudioProcessorTest {
// Given a signal with only noise.
InputBufferProvider
inputBufferProvider
=
getInputBufferProviderForAlternatingSilenceAndNoise
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
TEST_SIGNAL_SILENCE_DURATION_MS
,
/* noiseDurationMs= */
0
,
TEST_SIGNAL_FRAME_COUNT
);
// When processing the entire signal.
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
silenceSkippingAudioProcessor
.
flush
();
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
long
totalOutputFrames
=
...
...
@@ -113,8 +109,6 @@ public final class SilenceSkippingAudioProcessorTest {
// Given a signal with only silence.
InputBufferProvider
inputBufferProvider
=
getInputBufferProviderForAlternatingSilenceAndNoise
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
/* silenceDurationMs= */
0
,
TEST_SIGNAL_NOISE_DURATION_MS
,
TEST_SIGNAL_FRAME_COUNT
);
...
...
@@ -123,8 +117,7 @@ public final class SilenceSkippingAudioProcessorTest {
SilenceSkippingAudioProcessor
silenceSkippingAudioProcessor
=
new
SilenceSkippingAudioProcessor
();
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
silenceSkippingAudioProcessor
.
flush
();
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
long
totalOutputFrames
=
...
...
@@ -141,8 +134,6 @@ public final class SilenceSkippingAudioProcessorTest {
// Given a signal that alternates between silence and noise.
InputBufferProvider
inputBufferProvider
=
getInputBufferProviderForAlternatingSilenceAndNoise
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
TEST_SIGNAL_SILENCE_DURATION_MS
,
TEST_SIGNAL_NOISE_DURATION_MS
,
TEST_SIGNAL_FRAME_COUNT
);
...
...
@@ -151,8 +142,7 @@ public final class SilenceSkippingAudioProcessorTest {
SilenceSkippingAudioProcessor
silenceSkippingAudioProcessor
=
new
SilenceSkippingAudioProcessor
();
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
silenceSkippingAudioProcessor
.
flush
();
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
long
totalOutputFrames
=
...
...
@@ -169,8 +159,6 @@ public final class SilenceSkippingAudioProcessorTest {
// Given a signal that alternates between silence and noise.
InputBufferProvider
inputBufferProvider
=
getInputBufferProviderForAlternatingSilenceAndNoise
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
TEST_SIGNAL_SILENCE_DURATION_MS
,
TEST_SIGNAL_NOISE_DURATION_MS
,
TEST_SIGNAL_FRAME_COUNT
);
...
...
@@ -179,8 +167,7 @@ public final class SilenceSkippingAudioProcessorTest {
SilenceSkippingAudioProcessor
silenceSkippingAudioProcessor
=
new
SilenceSkippingAudioProcessor
();
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
silenceSkippingAudioProcessor
.
flush
();
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
long
totalOutputFrames
=
...
...
@@ -197,8 +184,6 @@ public final class SilenceSkippingAudioProcessorTest {
// Given a signal that alternates between silence and noise.
InputBufferProvider
inputBufferProvider
=
getInputBufferProviderForAlternatingSilenceAndNoise
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
TEST_SIGNAL_SILENCE_DURATION_MS
,
TEST_SIGNAL_NOISE_DURATION_MS
,
TEST_SIGNAL_FRAME_COUNT
);
...
...
@@ -207,8 +192,7 @@ public final class SilenceSkippingAudioProcessorTest {
SilenceSkippingAudioProcessor
silenceSkippingAudioProcessor
=
new
SilenceSkippingAudioProcessor
();
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
silenceSkippingAudioProcessor
.
flush
();
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
long
totalOutputFrames
=
...
...
@@ -224,8 +208,6 @@ public final class SilenceSkippingAudioProcessorTest {
// Given a signal that alternates between silence and noise.
InputBufferProvider
inputBufferProvider
=
getInputBufferProviderForAlternatingSilenceAndNoise
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
TEST_SIGNAL_SILENCE_DURATION_MS
,
TEST_SIGNAL_NOISE_DURATION_MS
,
TEST_SIGNAL_FRAME_COUNT
);
...
...
@@ -234,8 +216,7 @@ public final class SilenceSkippingAudioProcessorTest {
SilenceSkippingAudioProcessor
silenceSkippingAudioProcessor
=
new
SilenceSkippingAudioProcessor
();
silenceSkippingAudioProcessor
.
setEnabled
(
true
);
silenceSkippingAudioProcessor
.
configure
(
TEST_SIGNAL_SAMPLE_RATE_HZ
,
TEST_SIGNAL_CHANNEL_COUNT
,
C
.
ENCODING_PCM_16BIT
);
silenceSkippingAudioProcessor
.
configure
(
AUDIO_FORMAT
);
silenceSkippingAudioProcessor
.
flush
();
assertThat
(
silenceSkippingAudioProcessor
.
isActive
()).
isTrue
();
process
(
silenceSkippingAudioProcessor
,
inputBufferProvider
,
INPUT_BUFFER_SIZE
);
...
...
@@ -253,6 +234,7 @@ public final class SilenceSkippingAudioProcessorTest {
SilenceSkippingAudioProcessor
processor
,
InputBufferProvider
inputBufferProvider
,
int
inputBufferSize
)
{
int
bytesPerFrame
=
AUDIO_FORMAT
.
bytesPerFrame
;
processor
.
flush
();
long
totalOutputFrames
=
0
;
while
(
inputBufferProvider
.
hasRemaining
())
{
...
...
@@ -260,14 +242,14 @@ public final class SilenceSkippingAudioProcessorTest {
while
(
inputBuffer
.
hasRemaining
())
{
processor
.
queueInput
(
inputBuffer
);
ByteBuffer
outputBuffer
=
processor
.
getOutput
();
totalOutputFrames
+=
outputBuffer
.
remaining
()
/
(
2
*
processor
.
getOutputChannelCount
())
;
totalOutputFrames
+=
outputBuffer
.
remaining
()
/
bytesPerFrame
;
outputBuffer
.
clear
();
}
}
processor
.
queueEndOfStream
();
while
(!
processor
.
isEnded
())
{
ByteBuffer
outputBuffer
=
processor
.
getOutput
();
totalOutputFrames
+=
outputBuffer
.
remaining
()
/
(
2
*
processor
.
getOutputChannelCount
())
;
totalOutputFrames
+=
outputBuffer
.
remaining
()
/
bytesPerFrame
;
outputBuffer
.
clear
();
}
return
totalOutputFrames
;
...
...
@@ -278,16 +260,16 @@ public final class SilenceSkippingAudioProcessorTest {
* between silence/noise of the specified durations to fill {@code totalFrameCount}.
*/
private
static
InputBufferProvider
getInputBufferProviderForAlternatingSilenceAndNoise
(
int
sampleRateHz
,
int
channelCount
,
int
silenceDurationMs
,
int
noiseDurationMs
,
int
totalFrameCount
)
{
int
sampleRate
=
AUDIO_FORMAT
.
sampleRate
;
int
channelCount
=
AUDIO_FORMAT
.
channelCount
;
Pcm16BitAudioBuilder
audioBuilder
=
new
Pcm16BitAudioBuilder
(
channelCount
,
totalFrameCount
);
while
(!
audioBuilder
.
isFull
())
{
int
silenceDurationFrames
=
(
silenceDurationMs
*
sampleRate
Hz
)
/
1000
;
int
silenceDurationFrames
=
(
silenceDurationMs
*
sampleRate
)
/
1000
;
audioBuilder
.
appendFrames
(
/* count= */
silenceDurationFrames
,
/* channelLevels= */
(
short
)
0
);
int
noiseDurationFrames
=
(
noiseDurationMs
*
sampleRate
Hz
)
/
1000
;
int
noiseDurationFrames
=
(
noiseDurationMs
*
sampleRate
)
/
1000
;
audioBuilder
.
appendFrames
(
/* count= */
noiseDurationFrames
,
/* channelLevels= */
Short
.
MAX_VALUE
);
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/audio/SonicAudioProcessorTest.java
View file @
10f142b3
...
...
@@ -20,6 +20,8 @@ import static org.junit.Assert.fail;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat
;
import
com.google.android.exoplayer2.audio.AudioProcessor.UnhandledAudioFormatException
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
...
...
@@ -28,6 +30,16 @@ import org.junit.runner.RunWith;
@RunWith
(
AndroidJUnit4
.
class
)
public
final
class
SonicAudioProcessorTest
{
private
static
final
AudioFormat
AUDIO_FORMAT_22050_HZ
=
new
AudioFormat
(
/* sampleRate= */
22050
,
/* channelCount= */
2
,
/* encoding= */
C
.
ENCODING_PCM_16BIT
);
private
static
final
AudioFormat
AUDIO_FORMAT_44100_HZ
=
new
AudioFormat
(
/* sampleRate= */
44100
,
/* channelCount= */
2
,
/* encoding= */
C
.
ENCODING_PCM_16BIT
);
private
static
final
AudioFormat
AUDIO_FORMAT_48000_HZ
=
new
AudioFormat
(
/* sampleRate= */
48000
,
/* channelCount= */
2
,
/* encoding= */
C
.
ENCODING_PCM_16BIT
);
private
SonicAudioProcessor
sonicAudioProcessor
;
@Before
...
...
@@ -39,59 +51,36 @@ public final class SonicAudioProcessorTest {
public
void
testReconfigureWithSameSampleRate
()
throws
Exception
{
// When configured for resampling from 44.1 kHz to 48 kHz, the output sample rate is correct.
sonicAudioProcessor
.
setOutputSampleRateHz
(
48000
);
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
assertThat
(
sonicAudioProcessor
.
getOutputSampleRateHz
()).
isEqualTo
(
48000
);
AudioFormat
outputAudioFormat
=
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_44100_HZ
);
assertThat
(
sonicAudioProcessor
.
isActive
()).
isTrue
();
assertThat
(
outputAudioFormat
.
sampleRate
).
isEqualTo
(
48000
);
// When reconfigured with 48 kHz input, there is no resampling.
sonicAudioProcessor
.
configure
(
48000
,
2
,
C
.
ENCODING_PCM_16BIT
);
assertThat
(
sonicAudioProcessor
.
getOutputSampleRateHz
()).
isEqualTo
(
48000
);
outputAudioFormat
=
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_48000_HZ
);
assertThat
(
sonicAudioProcessor
.
isActive
()).
isFalse
();
assertThat
(
outputAudioFormat
.
sampleRate
).
isEqualTo
(
48000
);
// When reconfigure with 44.1 kHz input, resampling is enabled again.
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
assertThat
(
sonicAudioProcessor
.
getOutputSampleRateHz
()).
isEqualTo
(
48000
);
outputAudioFormat
=
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_44100_HZ
);
assertThat
(
sonicAudioProcessor
.
isActive
()).
isTrue
();
assertThat
(
outputAudioFormat
.
sampleRate
).
isEqualTo
(
48000
);
}
@Test
public
void
testNoSampleRateChange
()
throws
Exception
{
// Configure for resampling 44.1 kHz to 48 kHz.
sonicAudioProcessor
.
setOutputSampleRateHz
(
48000
);
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_44100_HZ
);
assertThat
(
sonicAudioProcessor
.
isActive
()).
isTrue
();
// Reconfigure to not modify the sample rate.
sonicAudioProcessor
.
setOutputSampleRateHz
(
SonicAudioProcessor
.
SAMPLE_RATE_NO_CHANGE
);
sonicAudioProcessor
.
configure
(
22050
,
2
,
C
.
ENCODING_PCM_16BIT
);
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_22050_HZ
);
// The sample rate is unmodified, and the audio processor is not active.
assertThat
(
sonicAudioProcessor
.
getOutputSampleRateHz
()).
isEqualTo
(
22050
);
assertThat
(
sonicAudioProcessor
.
isActive
()).
isFalse
();
}
@Test
public
void
testBecomesActiveAfterConfigure
()
throws
Exception
{
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
// Set a new sample rate.
sonicAudioProcessor
.
setOutputSampleRateHz
(
22050
);
// The new sample rate is not active yet.
assertThat
(
sonicAudioProcessor
.
isActive
()).
isFalse
();
assertThat
(
sonicAudioProcessor
.
getOutputSampleRateHz
()).
isEqualTo
(
44100
);
}
@Test
public
void
testSampleRateChangeBecomesActiveAfterConfigure
()
throws
Exception
{
// Configure for resampling 44.1 kHz to 48 kHz.
sonicAudioProcessor
.
setOutputSampleRateHz
(
48000
);
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
// Set a new sample rate, which isn't active yet.
sonicAudioProcessor
.
setOutputSampleRateHz
(
22050
);
assertThat
(
sonicAudioProcessor
.
getOutputSampleRateHz
()).
isEqualTo
(
48000
);
// The new sample rate takes effect on reconfiguration.
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
assertThat
(
sonicAudioProcessor
.
getOutputSampleRateHz
()).
isEqualTo
(
22050
);
}
@Test
public
void
testIsActiveWithSpeedChange
()
throws
Exception
{
sonicAudioProcessor
.
setSpeed
(
1.5f
);
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_44100_HZ
);
sonicAudioProcessor
.
flush
();
assertThat
(
sonicAudioProcessor
.
isActive
()).
isTrue
();
}
...
...
@@ -99,35 +88,45 @@ public final class SonicAudioProcessorTest {
@Test
public
void
testIsActiveWithPitchChange
()
throws
Exception
{
sonicAudioProcessor
.
setPitch
(
1.5f
);
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_44100_HZ
);
sonicAudioProcessor
.
flush
();
assertThat
(
sonicAudioProcessor
.
isActive
()).
isTrue
();
}
@Test
public
void
testIsNotActiveWithNoChange
()
throws
Exception
{
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_16BIT
);
sonicAudioProcessor
.
configure
(
AUDIO_FORMAT_44100_HZ
);
assertThat
(
sonicAudioProcessor
.
isActive
()).
isFalse
();
}
@Test
public
void
testDoesNotSupportNon16BitInput
()
throws
Exception
{
try
{
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_8BIT
);
sonicAudioProcessor
.
configure
(
new
AudioFormat
(
/* sampleRate= */
44100
,
/* channelCount= */
2
,
/* encoding= */
C
.
ENCODING_PCM_8BIT
));
fail
();
}
catch
(
AudioProcessor
.
Unhandled
FormatException
e
)
{
}
catch
(
UnhandledAudio
FormatException
e
)
{
// Expected.
}
try
{
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_24BIT
);
sonicAudioProcessor
.
configure
(
new
AudioFormat
(
/* sampleRate= */
44100
,
/* channelCount= */
2
,
/* encoding= */
C
.
ENCODING_PCM_24BIT
));
fail
();
}
catch
(
AudioProcessor
.
Unhandled
FormatException
e
)
{
}
catch
(
UnhandledAudio
FormatException
e
)
{
// Expected.
}
try
{
sonicAudioProcessor
.
configure
(
44100
,
2
,
C
.
ENCODING_PCM_32BIT
);
sonicAudioProcessor
.
configure
(
new
AudioFormat
(
/* sampleRate= */
44100
,
/* channelCount= */
2
,
/* encoding= */
C
.
ENCODING_PCM_32BIT
));
fail
();
}
catch
(
AudioProcessor
.
Unhandled
FormatException
e
)
{
}
catch
(
UnhandledAudio
FormatException
e
)
{
// Expected.
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment