summaryrefslogtreecommitdiffstats
path: root/chromecast
diff options
context:
space:
mode:
authorkmackay <kmackay@chromium.org>2016-03-20 15:58:27 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-20 22:59:19 +0000
commit57ae6f94ebb73d36acaef1e0cff68b3c43db98b4 (patch)
tree3e77889bb97360aad33a549e9f1fd935252c3518 /chromecast
parent9861e39f90174b134366db95471a64e0a474d874 (diff)
downloadchromium_src-57ae6f94ebb73d36acaef1e0cff68b3c43db98b4.zip
chromium_src-57ae6f94ebb73d36acaef1e0cff68b3c43db98b4.tar.gz
chromium_src-57ae6f94ebb73d36acaef1e0cff68b3c43db98b4.tar.bz2
[Chromecast] Add optional audio loopback support to the media shlib
This provides an API to get loopback audio (ie, mixed audio data from just before it is output), and an implementation for the ALSA CMA backend. This API is not required to be implemented by OEMs. BUG= internal b/27564892 Review URL: https://codereview.chromium.org/1790623002 Cr-Commit-Position: refs/heads/master@{#382235}
Diffstat (limited to 'chromecast')
-rw-r--r--chromecast/media/cma/backend/alsa/cast_media_shlib.cc10
-rw-r--r--chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc37
-rw-r--r--chromecast/media/cma/backend/alsa/stream_mixer_alsa.h9
-rw-r--r--chromecast/public/cast_media_shlib.h38
-rw-r--r--chromecast/public/media/decoder_config.h8
5 files changed, 93 insertions, 9 deletions
diff --git a/chromecast/media/cma/backend/alsa/cast_media_shlib.cc b/chromecast/media/cma/backend/alsa/cast_media_shlib.cc
index 2154b70..bb4c6b5 100644
--- a/chromecast/media/cma/backend/alsa/cast_media_shlib.cc
+++ b/chromecast/media/cma/backend/alsa/cast_media_shlib.cc
@@ -12,6 +12,7 @@
#include "base/thread_task_runner_handle.h"
#include "chromecast/base/task_runner_impl.h"
#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h"
+#include "chromecast/media/cma/backend/alsa/stream_mixer_alsa.h"
#include "chromecast/public/cast_media_shlib.h"
#include "chromecast/public/graphics_types.h"
#include "chromecast/public/media_codec_support_shlib.h"
@@ -190,5 +191,14 @@ bool CastMediaShlib::SupportsMediaClockRateChange() {
return g_rate_offset_element != nullptr;
}
+void CastMediaShlib::AddLoopbackAudioObserver(LoopbackAudioObserver* observer) {
+ StreamMixerAlsa::Get()->AddLoopbackAudioObserver(observer);
+}
+
+void CastMediaShlib::RemoveLoopbackAudioObserver(
+ LoopbackAudioObserver* observer) {
+ StreamMixerAlsa::Get()->RemoveLoopbackAudioObserver(observer);
+}
+
} // namespace media
} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
index 5e5e17b..0c5e4b6 100644
--- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
+++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.cc
@@ -720,12 +720,20 @@ void StreamMixerAlsa::WriteMixedPcm(const ::media::AudioBus& mixed,
DCHECK(mixer_task_runner_->BelongsToCurrentThread());
CHECK_PCM_INITIALIZED();
- if (interleaved_.size() < static_cast<size_t>(frames * num_output_channels_) *
- BytesPerOutputFormatSample()) {
- interleaved_.resize(frames * num_output_channels_ *
- BytesPerOutputFormatSample());
+ size_t interleaved_size = static_cast<size_t>(frames * num_output_channels_) *
+ BytesPerOutputFormatSample();
+ if (interleaved_.size() < interleaved_size)
+ interleaved_.resize(interleaved_size);
+
+ int64_t expected_playback_time = rendering_delay_.timestamp_microseconds +
+ rendering_delay_.delay_microseconds;
+ mixed.ToInterleaved(frames, BytesPerOutputFormatSample(),
+ interleaved_.data());
+ for (CastMediaShlib::LoopbackAudioObserver* observer : loopback_observers_) {
+ observer->OnLoopbackAudio(expected_playback_time, kSampleFormatS32,
+ output_samples_per_second_, num_output_channels_,
+ interleaved_.data(), interleaved_size);
}
- mixed.ToInterleaved(frames, BytesPerOutputFormatSample(), &interleaved_[0]);
// If the PCM has been drained it will be in SND_PCM_STATE_SETUP and need
// to be prepared in order for playback to work.
@@ -772,5 +780,24 @@ void StreamMixerAlsa::UpdateRenderingDelay(int newly_pushed_frames) {
output_samples_per_second_;
}
+void StreamMixerAlsa::AddLoopbackAudioObserver(
+ CastMediaShlib::LoopbackAudioObserver* observer) {
+ RUN_ON_MIXER_THREAD(&StreamMixerAlsa::AddLoopbackAudioObserver, observer);
+ DCHECK(observer);
+ if (std::find(loopback_observers_.begin(), loopback_observers_.end(),
+ observer) != loopback_observers_.end()) {
+ return; // Don't add the observer again if it is already in the list.
+ }
+ loopback_observers_.push_back(observer);
+}
+
+void StreamMixerAlsa::RemoveLoopbackAudioObserver(
+ CastMediaShlib::LoopbackAudioObserver* observer) {
+ RUN_ON_MIXER_THREAD(&StreamMixerAlsa::RemoveLoopbackAudioObserver, observer);
+ loopback_observers_.erase(std::remove(loopback_observers_.begin(),
+ loopback_observers_.end(), observer),
+ loopback_observers_.end());
+}
+
} // namespace media
} // namespace chromecast
diff --git a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
index b344da3..fec3d79 100644
--- a/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
+++ b/chromecast/media/cma/backend/alsa/stream_mixer_alsa.h
@@ -18,6 +18,7 @@
#include "base/threading/thread.h"
#include "base/timer/timer.h"
#include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h"
+#include "chromecast/public/cast_media_shlib.h"
namespace media {
class AudioBus;
@@ -140,6 +141,12 @@ class StreamMixerAlsa {
void WriteFramesForTest(); // Can be called on any thread.
void ClearInputsForTest(); // Removes all inputs.
+ void AddLoopbackAudioObserver(
+ CastMediaShlib::LoopbackAudioObserver* observer);
+
+ void RemoveLoopbackAudioObserver(
+ CastMediaShlib::LoopbackAudioObserver* observer);
+
protected:
StreamMixerAlsa();
virtual ~StreamMixerAlsa();
@@ -223,6 +230,8 @@ class StreamMixerAlsa {
int check_close_timeout_;
scoped_ptr<base::Timer> check_close_timer_;
+ std::vector<CastMediaShlib::LoopbackAudioObserver*> loopback_observers_;
+
DISALLOW_COPY_AND_ASSIGN(StreamMixerAlsa);
};
diff --git a/chromecast/public/cast_media_shlib.h b/chromecast/public/cast_media_shlib.h
index ca11f49..e39057b 100644
--- a/chromecast/public/cast_media_shlib.h
+++ b/chromecast/public/cast_media_shlib.h
@@ -5,6 +5,8 @@
#ifndef CHROMECAST_PUBLIC_CAST_MEDIA_SHLIB_H_
#define CHROMECAST_PUBLIC_CAST_MEDIA_SHLIB_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
@@ -13,6 +15,8 @@
namespace chromecast {
namespace media {
+enum SampleFormat : int;
+
class MediaPipelineBackend;
struct MediaPipelineDeviceParams;
class VideoPlane;
@@ -28,6 +32,28 @@ class VideoPlane;
// from other tests.
class CHROMECAST_EXPORT CastMediaShlib {
public:
+ // Observer for audio loopback data.
+ class LoopbackAudioObserver {
+ public:
+ // Called whenever audio data is about to be output. The |timestamp| is the
+ // estimated time in microseconds (relative to CLOCK_MONOTONIC_RAW) that
+ // the audio will actually be output. |length| is the length of |data| in
+ // bytes. The format and sample rate of |data| are determined when calling
+ // AddLoopbackAudioObserver(); the number of channels is constant for the
+ // system (AddLoopbackAudioObserver() provides the number of channels).
+ // This method is called on the audio output thread, and MUST not block
+ // or take very much time (or audio underruns will occur).
+ virtual void OnLoopbackAudio(int64_t timestamp,
+ SampleFormat sample_format,
+ int sample_rate,
+ int num_channels,
+ uint8_t* data,
+ int length) = 0;
+
+ protected:
+ virtual ~LoopbackAudioObserver() {}
+ };
+
// Initializes platform-specific media systems. Only called when in an
// uninitialized state.
static void Initialize(const std::vector<std::string>& argv);
@@ -62,6 +88,18 @@ class CHROMECAST_EXPORT CastMediaShlib {
// Tests if the implementation supports renderer clock rate adjustments.
static bool SupportsMediaClockRateChange();
+
+ // Adds a loopback audio observer. Adding the same observer more than
+ // once has no effect.
+ // This function is optional to implement.
+ static void AddLoopbackAudioObserver(LoopbackAudioObserver* observer)
+ __attribute__((__weak__));
+
+ // Removes a loopback audio observer. It is not an error to remove an observer
+ // that was never added, or to remove the same observer more than once.
+ // This function is optional to implement.
+ static void RemoveLoopbackAudioObserver(LoopbackAudioObserver* observer)
+ __attribute__((__weak__));
};
} // namespace media
diff --git a/chromecast/public/media/decoder_config.h b/chromecast/public/media/decoder_config.h
index b82c5c1..d863fac 100644
--- a/chromecast/public/media/decoder_config.h
+++ b/chromecast/public/media/decoder_config.h
@@ -19,7 +19,7 @@ static const int kMaxBytesPerSample = 4;
// Maximum audio sampling rate.
static const int kMaxSampleRate = 192000;
-enum AudioCodec {
+enum AudioCodec : int {
kAudioCodecUnknown = 0,
kCodecAAC,
kCodecMP3,
@@ -36,7 +36,7 @@ enum AudioCodec {
kAudioCodecMax = kCodecFLAC,
};
-enum SampleFormat {
+enum SampleFormat : int {
kUnknownSampleFormat = 0,
kSampleFormatU8, // Unsigned 8-bit w/ bias of 128.
kSampleFormatS16, // Signed 16-bit.
@@ -51,7 +51,7 @@ enum SampleFormat {
kSampleFormatMax = kSampleFormatS24,
};
-enum VideoCodec {
+enum VideoCodec : int {
kVideoCodecUnknown = 0,
kCodecH264,
kCodecVC1,
@@ -69,7 +69,7 @@ enum VideoCodec {
};
// Profile for Video codec.
-enum VideoProfile {
+enum VideoProfile : int {
kVideoProfileUnknown = 0,
kH264Baseline,
kH264Main,