Add tee sink to SpdifStreamOut
Test: enable per https://source.android.com/docs/core/audio/debugging
play ac3 track via SpdifStreamOut using
AudioTrackSurroundTest#testPlayAC3Bytes
dumpsys media.audio_flinger and see .raw iec61937 wrapped
file in /data/misc/audioserver.
Change-Id: I65ccd9d8a5b92ef7ffc87e081095d8f7332d8acb
diff --git a/services/audioflinger/afutils/NBAIO_Tee.cpp b/services/audioflinger/afutils/NBAIO_Tee.cpp
index 49057ce..86fb128 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.cpp
+++ b/services/audioflinger/afutils/NBAIO_Tee.cpp
@@ -43,6 +43,7 @@
"aftee_Date_ThreadId_C_reason.wav" RecordThread
"aftee_Date_ThreadId_M_reason.wav" MixerThread (Normal)
"aftee_Date_ThreadId_F_reason.wav" MixerThread (Fast)
+ "aftee_Date_ThreadId_D_reason.raw" DirectOutputThread (SpdifStreamOut)
"aftee_Date_ThreadId_TrackId_R_reason.wav" RecordTrack
"aftee_Date_ThreadId_TrackId_TrackName_T_reason.wav" PlaybackTrack
@@ -120,7 +121,7 @@
return directory.size() > 0 && directory[0] == '/';
}
- std::string generateFilename(const std::string &suffix) const {
+ std::string generateFilename(const std::string &suffix, audio_format_t format) const {
char fileTime[sizeof("YYYYmmdd_HHMMSS_\0")];
struct timeval tv;
gettimeofday(&tv, nullptr /* struct timezone */);
@@ -130,7 +131,7 @@
"incorrect fileTime buffer");
char msec[4];
(void)snprintf(msec, sizeof(msec), "%03d", (int)(tv.tv_usec / 1000));
- return mPrefix + fileTime + msec + suffix + ".wav";
+ return mPrefix + fileTime + msec + suffix + (audio_is_linear_pcm(format) ? ".wav" : ".raw");
}
bool isManagedFilename(const char *name) {
@@ -225,7 +226,7 @@
NBAIO_Tee::NBAIO_TeeImpl::NBAIO_SinkSource NBAIO_Tee::NBAIO_TeeImpl::makeSinkSource(
const NBAIO_Format &format, size_t frames, bool *enabled)
{
- if (Format_isValid(format) && audio_is_linear_pcm(format.mFormat)) {
+ if (Format_isValid(format) && audio_has_proportional_frames(format.mFormat)) {
Pipe *pipe = new Pipe(frames, format);
size_t numCounterOffers = 0;
const NBAIO_Format offers[1] = {format};
@@ -259,7 +260,7 @@
audio_format_t format,
const std::string &suffix)
{
- std::string filename = generateFilename(suffix);
+ std::string filename = generateFilename(suffix, format);
if (mThreadPool.launch(std::string("create ") + filename,
[=]() { return createInternal(reader, sampleRate, channelCount, format, filename); })
@@ -406,6 +407,7 @@
switch (format) {
case AUDIO_FORMAT_PCM_8_BIT:
case AUDIO_FORMAT_PCM_16_BIT:
+ case AUDIO_FORMAT_IEC61937:
sf_format = SF_FORMAT_PCM_16;
writeFormat = AUDIO_FORMAT_PCM_16_BIT;
ALOGV("%s: %s using PCM_16 for format %#x", __func__, filename.c_str(), format);
@@ -424,7 +426,6 @@
break;
default:
// TODO:
- // handle audio_has_proportional_frames() formats.
// handle compressed formats as single byte files.
return BAD_VALUE;
}
@@ -440,7 +441,7 @@
.frames = 0,
.samplerate = (int)sampleRate,
.channels = (int)channelCount,
- .format = SF_FORMAT_WAV | sf_format,
+ .format = sf_format | (audio_is_linear_pcm(format) ? SF_FORMAT_WAV : 0 /* RAW */),
};
SNDFILE *sf = sf_open(path.c_str(), SFM_WRITE, &info);
if (sf == nullptr) {
@@ -463,7 +464,7 @@
}
// Convert input format to writeFormat as needed.
- if (format != writeFormat) {
+ if (format != writeFormat && audio_is_linear_pcm(format)) {
memcpy_by_audio_format(
buffer, writeFormat, buffer, format, actualRead * info.channels);
}
diff --git a/services/audioflinger/afutils/NBAIO_Tee.h b/services/audioflinger/afutils/NBAIO_Tee.h
index 17b6175..1133671 100644
--- a/services/audioflinger/afutils/NBAIO_Tee.h
+++ b/services/audioflinger/afutils/NBAIO_Tee.h
@@ -48,7 +48,7 @@
*
* Some AudioFlinger specific notes:
*
- * 1) Tees capture only linear PCM data.
+ * 1) Tees capture only linear PCM or IEC61937 data.
* 2) Tees without any data written are considered empty and do not generate
* any output files.
* 2) Once a Tee dumps data, it is considered "emptied" and new data
@@ -58,6 +58,7 @@
* WAV integer PCM 32 bit for AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED
* AUDIO_FORMAT_PCM_32_BIT.
* WAV float PCM 32 bit for AUDIO_FORMAT_PCM_FLOAT.
+ * RAW for AUDIO_FORMAT_IEC61937.
*
* Input_Thread:
* 1) Capture buffer is teed when read from the HAL, before resampling for the AudioRecord
@@ -68,8 +69,8 @@
* NormalMixer output (if no FastMixer).
* 2) DuplicatingThreads do not tee any mixed data. Apply a tee on the downstream OutputTrack
* or on the upstream playback Tracks.
- * 3) DirectThreads and OffloadThreads do not tee any data. The upstream track
- * (if linear PCM format) may be teed to discover data.
+ * 3) DirectThreads and OffloadThreads with SpdifStreamOut will tee IEC61937 wrapped data.
+ * Otherwise, the upstream track (if linear PCM format) may be teed to discover data.
* 4) MmapThreads are not supported.
*
* Tracks:
diff --git a/services/audioflinger/datapath/Android.bp b/services/audioflinger/datapath/Android.bp
index 58f0422..ee98aef 100644
--- a/services/audioflinger/datapath/Android.bp
+++ b/services/audioflinger/datapath/Android.bp
@@ -55,10 +55,18 @@
shared_libs: [
"audioclient-types-aidl-cpp",
"av-types-aidl-cpp",
+ "libaudioflinger_utils", // NBAIO_Tee
+ "libaudioprocessing",
"libaudiospdif",
"libaudioutils",
"libbase",
+ "libcutils",
"liblog",
+ "libnbaio",
"libutils", // refbase
],
+
+ include_dirs: [
+ "frameworks/av/services/audioflinger", // for configuration
+ ],
}
diff --git a/services/audioflinger/datapath/SpdifStreamOut.cpp b/services/audioflinger/datapath/SpdifStreamOut.cpp
index 43e9c0c..6bc1f2d 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.cpp
+++ b/services/audioflinger/datapath/SpdifStreamOut.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+#include "Configuration.h"
#include <system/audio.h>
#include <utils/Log.h>
@@ -96,6 +97,16 @@
ALOGI("SpdifStreamOut::open() status = %d", status);
+#ifdef TEE_SINK
+ if (status == OK) {
+ // Don't use PCM 16-bit format to avoid WAV encoding IEC61937 data.
+ mTee.set(customConfig.sample_rate,
+ audio_channel_count_from_out_mask(customConfig.channel_mask),
+ AUDIO_FORMAT_IEC61937, NBAIO_Tee::TEE_FLAG_OUTPUT_THREAD);
+ mTee.setId(std::string("_") + std::to_string(handle) + "_D");
+ }
+#endif
+
return status;
}
@@ -113,7 +124,15 @@
ssize_t SpdifStreamOut::writeDataBurst(const void* buffer, size_t bytes)
{
- return AudioStreamOut::write(buffer, bytes);
+ const ssize_t written = AudioStreamOut::write(buffer, bytes);
+
+#ifdef TEE_SINK
+ if (written > 0) {
+ mTee.write(reinterpret_cast<const char *>(buffer),
+ written / AudioStreamOut::getFrameSize());
+ }
+#endif
+ return written;
}
ssize_t SpdifStreamOut::write(const void* buffer, size_t numBytes)
diff --git a/services/audioflinger/datapath/SpdifStreamOut.h b/services/audioflinger/datapath/SpdifStreamOut.h
index c8dc89f..1640575 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.h
+++ b/services/audioflinger/datapath/SpdifStreamOut.h
@@ -25,6 +25,7 @@
#include "AudioStreamOut.h"
+#include <afutils/NBAIO_Tee.h>
#include <audio_utils/spdif/SPDIFEncoder.h>
namespace android {
@@ -116,6 +117,10 @@
ssize_t writeDataBurst(const void* data, size_t bytes);
ssize_t writeInternal(const void* buffer, size_t bytes);
+#ifdef TEE_SINK
+ NBAIO_Tee mTee;
+#endif
+
};
} // namespace android