summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/AudioFlinger.cpp
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2014-06-20 18:31:16 -0700
committerEric Laurent <elaurent@google.com>2014-07-24 02:56:47 +0000
commit83b8808faad1e91690c64d7007348be8d9ebde73 (patch)
treeb541b1172f804e04bd19b29f7878a1becf6205d7 /services/audioflinger/AudioFlinger.cpp
parentc15c265676da2226a18a5373812608b19d4719d7 (diff)
downloadframeworks_av-83b8808faad1e91690c64d7007348be8d9ebde73.zip
frameworks_av-83b8808faad1e91690c64d7007348be8d9ebde73.tar.gz
frameworks_av-83b8808faad1e91690c64d7007348be8d9ebde73.tar.bz2
audio flinger: add patch connection between hw modules
Add support for audio device connections between different audio hw modules. The patch is performed by creating a bridge between the playback thread connected to the sink device and the record thread connected to the source device using a pair of specialized PlaybackTrack and RecordTrack. - Added PatchTrack and PatchRecord classes. - Added TrackBase type to indicate more clearly the track behavior. - A TrackBase can allocate the buffer or reuse an existing one. - Factored some code in openOutput() and openInput() for internal use by PatchPanel. Bug: 14815883. Change-Id: Ib9515fcda864610458a4bc81fa8f59096ff4d7db
Diffstat (limited to 'services/audioflinger/AudioFlinger.cpp')
-rw-r--r--services/audioflinger/AudioFlinger.cpp227
1 files changed, 140 insertions, 87 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1ad6285..8bf709e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1531,7 +1531,7 @@ audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
}
audio_module_handle_t handle = nextUniqueId();
- mAudioHwDevs.add(handle, new AudioHwDevice(name, dev, flags));
+ mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
ALOGI("loadHwModule() Loaded %s audio interface from %s (%s) handle %d",
name, dev->common.module->name, dev->common.module->id, handle);
@@ -1575,41 +1575,13 @@ status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice)
// ----------------------------------------------------------------------------
-audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
- audio_devices_t *pDevices,
- uint32_t *pSamplingRate,
- audio_format_t *pFormat,
- audio_channel_mask_t *pChannelMask,
- uint32_t *pLatencyMs,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo)
-{
- struct audio_config config;
- memset(&config, 0, sizeof(config));
- config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
- config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
- config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
- if (offloadInfo != NULL) {
- config.offload_info = *offloadInfo;
- }
-
- ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
- module,
- (pDevices != NULL) ? *pDevices : 0,
- config.sample_rate,
- config.format,
- config.channel_mask,
- flags);
- ALOGV("openOutput(), offloadInfo %p version 0x%04x",
- offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version);
-
- if (pDevices == NULL || *pDevices == AUDIO_DEVICE_NONE) {
- return AUDIO_IO_HANDLE_NONE;
- }
-
- Mutex::Autolock _l(mLock);
- AudioHwDevice *outHwDev = findSuitableHwDev_l(module, *pDevices);
+sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_t module,
+ audio_devices_t device,
+ struct audio_config *config,
+ audio_output_flags_t flags)
+{
+ AudioHwDevice *outHwDev = findSuitableHwDev_l(module, device);
if (outHwDev == NULL) {
return AUDIO_IO_HANDLE_NONE;
}
@@ -1635,18 +1607,18 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
status_t status = hwDevHal->open_output_stream(hwDevHal,
id,
- *pDevices,
- (audio_output_flags_t)flags,
- &config,
+ device,
+ flags,
+ config,
&outStream);
mHardwareStatus = AUDIO_HW_IDLE;
- ALOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %#08x, "
+ ALOGV("openOutput_l() openOutputStream returned output %p, SamplingRate %d, Format %#08x, "
"Channels %x, status %d",
outStream,
- config.sample_rate,
- config.format,
- config.channel_mask,
+ config->sample_rate,
+ config->format,
+ config->channel_mask,
status);
if (status == NO_ERROR && outStream != NULL) {
@@ -1654,19 +1626,60 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
PlaybackThread *thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
- thread = new OffloadThread(this, output, id, *pDevices);
+ thread = new OffloadThread(this, output, id, device);
ALOGV("openOutput() created offload output: ID %d thread %p", id, thread);
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
- || !isValidPcmSinkFormat(config.format)
- || (config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
- thread = new DirectOutputThread(this, output, id, *pDevices);
+ || !isValidPcmSinkFormat(config->format)
+ || (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
+ thread = new DirectOutputThread(this, output, id, device);
ALOGV("openOutput() created direct output: ID %d thread %p", id, thread);
} else {
- thread = new MixerThread(this, output, id, *pDevices);
+ thread = new MixerThread(this, output, id, device);
ALOGV("openOutput() created mixer output: ID %d thread %p", id, thread);
}
mPlaybackThreads.add(id, thread);
+ return thread;
+ }
+
+ return 0;
+}
+
+audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo)
+{
+ struct audio_config config;
+ memset(&config, 0, sizeof(config));
+ config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
+ config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
+ config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
+ if (offloadInfo != NULL) {
+ config.offload_info = *offloadInfo;
+ }
+ ALOGV("openOutput(), module %d Device %x, SamplingRate %d, Format %#08x, Channels %x, flags %x",
+ module,
+ (pDevices != NULL) ? *pDevices : 0,
+ config.sample_rate,
+ config.format,
+ config.channel_mask,
+ flags);
+ ALOGV("openOutput(), offloadInfo %p version 0x%04x",
+ offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version);
+
+ if (pDevices == NULL || *pDevices == AUDIO_DEVICE_NONE) {
+ return AUDIO_IO_HANDLE_NONE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ sp<PlaybackThread> thread = openOutput_l(module, *pDevices, &config, flags);
+ if (thread != 0) {
if (pSamplingRate != NULL) {
*pSamplingRate = config.sample_rate;
}
@@ -1686,16 +1699,16 @@ audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
// the first primary output opened designates the primary hw device
if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
ALOGI("Using module %d has the primary audio interface", module);
- mPrimaryHardwareDev = outHwDev;
+ mPrimaryHardwareDev = thread->getOutput()->audioHwDev;
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_MODE;
- hwDevHal->set_mode(hwDevHal, mMode);
+ mPrimaryHardwareDev->hwDevice()->set_mode(mPrimaryHardwareDev->hwDevice(), mMode);
mHardwareStatus = AUDIO_HW_IDLE;
mPrimaryOutputSampleRate = config.sample_rate;
}
- return id;
+ return thread->id();
}
return AUDIO_IO_HANDLE_NONE;
@@ -1776,15 +1789,29 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
// but the ThreadBase container still exists.
if (thread->type() != ThreadBase::DUPLICATING) {
- AudioStreamOut *out = thread->clearOutput();
- ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
- // from now on thread->mOutput is NULL
- out->hwDev()->close_output_stream(out->hwDev(), out->stream);
- delete out;
+ closeOutputFinish(thread);
}
+
+ thread.clear();
return NO_ERROR;
}
+void AudioFlinger::closeOutputFinish(sp<PlaybackThread> thread)
+{
+ AudioStreamOut *out = thread->clearOutput();
+ ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
+ // from now on thread->mOutput is NULL
+ out->hwDev()->close_output_stream(out->hwDev(), out->stream);
+ delete out;
+}
+
+void AudioFlinger::closeOutputInternal_l(sp<PlaybackThread> thread)
+{
+ mPlaybackThreads.removeItem(thread->mId);
+ thread->exit();
+ closeOutputFinish(thread);
+}
+
status_t AudioFlinger::suspendOutput(audio_io_handle_t output)
{
Mutex::Autolock _l(mLock);
@@ -1823,6 +1850,12 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
audio_channel_mask_t *pChannelMask,
audio_input_flags_t flags)
{
+ Mutex::Autolock _l(mLock);
+
+ if (pDevices == NULL || *pDevices == AUDIO_DEVICE_NONE) {
+ return AUDIO_IO_HANDLE_NONE;
+ }
+
struct audio_config config;
memset(&config, 0, sizeof(config));
config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
@@ -1833,13 +1866,36 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
audio_format_t reqFormat = config.format;
audio_channel_mask_t reqChannelMask = config.channel_mask;
- if (pDevices == NULL || *pDevices == AUDIO_DEVICE_NONE) {
- return 0;
+ sp<RecordThread> thread = openInput_l(module, *pDevices, &config, flags);
+
+ if (thread != 0) {
+ if (pSamplingRate != NULL) {
+ *pSamplingRate = reqSamplingRate;
+ }
+ if (pFormat != NULL) {
+ *pFormat = config.format;
+ }
+ if (pChannelMask != NULL) {
+ *pChannelMask = reqChannelMask;
+ }
+
+ // notify client processes of the new input creation
+ thread->audioConfigChanged(AudioSystem::INPUT_OPENED);
+ return thread->id();
}
+ return AUDIO_IO_HANDLE_NONE;
+}
- Mutex::Autolock _l(mLock);
+sp<AudioFlinger::RecordThread> AudioFlinger::openInput_l(audio_module_handle_t module,
+ audio_devices_t device,
+ struct audio_config *config,
+ audio_input_flags_t flags)
+{
+ uint32_t reqSamplingRate = config->sample_rate;
+ audio_format_t reqFormat = config->format;
+ audio_channel_mask_t reqChannelMask = config->channel_mask;
- AudioHwDevice *inHwDev = findSuitableHwDev_l(module, *pDevices);
+ AudioHwDevice *inHwDev = findSuitableHwDev_l(module, device);
if (inHwDev == NULL) {
return 0;
}
@@ -1848,14 +1904,14 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
audio_io_handle_t id = nextUniqueId();
audio_stream_in_t *inStream = NULL;
- status_t status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
+ status_t status = inHwHal->open_input_stream(inHwHal, id, device, config,
&inStream, flags);
ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %#x, Channels %x, "
"flags %#x, status %d",
inStream,
- config.sample_rate,
- config.format,
- config.channel_mask,
+ config->sample_rate,
+ config->format,
+ config->channel_mask,
flags,
status);
@@ -1863,14 +1919,14 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
// conversion internally, try to open again with the proposed parameters. The AudioFlinger can
// resample the input and do mono to stereo or stereo to mono conversions on 16 bit PCM inputs.
if (status == BAD_VALUE &&
- reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
- (config.sample_rate <= 2 * reqSamplingRate) &&
- (audio_channel_count_from_in_mask(config.channel_mask) <= FCC_2) &&
+ reqFormat == config->format && config->format == AUDIO_FORMAT_PCM_16_BIT &&
+ (config->sample_rate <= 2 * reqSamplingRate) &&
+ (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_2) &&
(audio_channel_count_from_in_mask(reqChannelMask) <= FCC_2)) {
// FIXME describe the change proposed by HAL (save old values so we can log them here)
ALOGV("openInput() reopening with proposed sampling rate and channel mask");
inStream = NULL;
- status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream, flags);
+ status = inHwHal->open_input_stream(inHwHal, id, device, config, &inStream, flags);
// FIXME log this new status; HAL should not propose any further changes
}
@@ -1931,30 +1987,18 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
// Start record thread
// RecordThread requires both input and output device indication to forward to audio
// pre processing modules
- RecordThread *thread = new RecordThread(this,
+ sp<RecordThread> thread = new RecordThread(this,
input,
id,
primaryOutputDevice_l(),
- *pDevices
+ device
#ifdef TEE_SINK
, teeSink
#endif
);
mRecordThreads.add(id, thread);
- ALOGV("openInput() created record thread: ID %d thread %p", id, thread);
- if (pSamplingRate != NULL) {
- *pSamplingRate = reqSamplingRate;
- }
- if (pFormat != NULL) {
- *pFormat = config.format;
- }
- if (pChannelMask != NULL) {
- *pChannelMask = reqChannelMask;
- }
-
- // notify client processes of the new input creation
- thread->audioConfigChanged(AudioSystem::INPUT_OPENED);
- return id;
+ ALOGV("openInput() created record thread: ID %d thread %p", id, thread.get());
+ return thread;
}
return 0;
@@ -1981,17 +2025,26 @@ status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
audioConfigChanged(AudioSystem::INPUT_CLOSED, input, NULL);
mRecordThreads.removeItem(input);
}
- thread->exit();
- // The thread entity (active unit of execution) is no longer running here,
- // but the ThreadBase container still exists.
+ // FIXME: calling thread->exit() without mLock held should not be needed anymore now that
+ // we have a different lock for notification client
+ closeInputFinish(thread);
+ return NO_ERROR;
+}
+void AudioFlinger::closeInputFinish(sp<RecordThread> thread)
+{
+ thread->exit();
AudioStreamIn *in = thread->clearInput();
ALOG_ASSERT(in != NULL, "in shouldn't be NULL");
// from now on thread->mInput is NULL
in->hwDev()->close_input_stream(in->hwDev(), in->stream);
delete in;
+}
- return NO_ERROR;
+void AudioFlinger::closeInputInternal_l(sp<RecordThread> thread)
+{
+ mRecordThreads.removeItem(thread->mId);
+ closeInputFinish(thread);
}
status_t AudioFlinger::invalidateStream(audio_stream_type_t stream)