first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,557 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#include <AssertMacros.h>
|
||||
|
||||
#include <platform/memmap.h>
|
||||
#include <platform.h>
|
||||
|
||||
#include <sys/task.h>
|
||||
|
||||
#include <iop.h>
|
||||
#include <qwi.h>
|
||||
#include <EmbeddedIOPProtocol.h>
|
||||
#include <arch.h>
|
||||
|
||||
#include "iop_audio_protocol.h"
|
||||
#include "AudioCodecA5.h"
|
||||
#include "clock_stepping.h"
|
||||
|
||||
#ifdef DO_PROFILING
|
||||
|
||||
// doing peak heap check requires heap.c to support it
|
||||
//#define DO_PEAKHEAPCHECK
|
||||
// doing peak heap check requires task.c to support it
|
||||
//#define DO_PEAKSTACKCHECK
|
||||
|
||||
#include <platform/timer.h>
|
||||
#include <arch/arm/arm.h>
|
||||
|
||||
#define kPerformanceSize 16
|
||||
struct PerformanceDetails
|
||||
{
|
||||
bool valid;
|
||||
utime_t time;
|
||||
uint32_t cycles;
|
||||
};
|
||||
|
||||
struct PerformanceDetails performanceDetails[kPerformanceSize];
|
||||
|
||||
void PerformanceSnapShotReset()
|
||||
{
|
||||
memset(performanceDetails, 0, sizeof(performanceDetails));
|
||||
}
|
||||
|
||||
void PerformanceSnapShotStart(uint32_t which)
|
||||
{
|
||||
if (which >= kPerformanceSize)
|
||||
return;
|
||||
performanceDetails[which].time = system_time();
|
||||
performanceDetails[which].cycles = arm_read_pmreg(ARM_PMCCNTR);
|
||||
}
|
||||
|
||||
void PerformanceSnapShotEnd(uint32_t which)
|
||||
{
|
||||
if (which >= kPerformanceSize)
|
||||
return;
|
||||
performanceDetails[which].valid = true;
|
||||
performanceDetails[which].time = system_time() - performanceDetails[which].time;
|
||||
performanceDetails[which].cycles = arm_read_pmreg(ARM_PMCCNTR) - performanceDetails[which].cycles;
|
||||
}
|
||||
|
||||
void SetupProfiling(IOPAUDIO_METRICS* metrics)
|
||||
{
|
||||
// mapping from enum to event monitors from the A5 TRM
|
||||
static const uint32_t eventtable[ACLKCycles-ICacheAccesses] = { 0x14, 0x1, 0x4, 0x3, 0x6, 0x7, 0xF, 0x8, 0x12, 0x10 };
|
||||
|
||||
// reset our user defined performance counters.
|
||||
PerformanceSnapShotReset();
|
||||
|
||||
// select wich events we are going to monitor
|
||||
uint32_t evt0 = 0x03; // by default we measure dcache fills
|
||||
uint32_t evt1 = 0x04; // by default we measure dcache accesses
|
||||
uint32_t i = ICacheAccesses;
|
||||
// choose the event monitor to follow. We only choose the first two we find
|
||||
for (;i < ACLKCycles; ++i)
|
||||
{
|
||||
if (metrics->mMetricsItemsValid & (1 << i))
|
||||
{
|
||||
evt0 = eventtable[(i - ICacheAccesses)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
for (;i < ACLKCycles; ++i)
|
||||
{
|
||||
if (metrics->mMetricsItemsValid & (1 << i))
|
||||
{
|
||||
evt1 = eventtable[(i - ICacheAccesses)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DO_PEAKSTACKCHECK
|
||||
if (metrics->mMetricsItemsValid & (1<<PeakStackUsage))
|
||||
reset_stack_usage("audio", 1024);
|
||||
#endif // DO_PEAKSTACKCHECK
|
||||
#ifdef DO_PEAKHEAPCHECK
|
||||
if (metrics->mMetricsItemsValid & (1<<PeakHeapUsage))
|
||||
heap_reset_peak_mem();
|
||||
#endif // DO_PEAKHEAPCHECK
|
||||
|
||||
arm_write_pmreg(ARM_PMOVSR, ~0); /* clear overflow status */
|
||||
arm_write_pmreg(ARM_PMSELR, 0); /* set event 0... */
|
||||
arm_write_pmreg(ARM_PMXEVTYPER, evt0);
|
||||
arm_write_pmreg(ARM_PMSELR, 1); /* set event 1... */
|
||||
arm_write_pmreg(ARM_PMXEVTYPER, evt1);
|
||||
arm_write_pmreg(ARM_PMCNTENSET, (1<<31) | (1<<1) | (1<<0)); /* enable cycles and events 0 and 1 */
|
||||
arm_write_pmreg(ARM_PMCR, 2); /* clear counters */
|
||||
arm_write_pmreg(ARM_PMCR, 1); /* enable all enabled counters */
|
||||
metrics->mMetricsFields[ProcessTimeUSec] = system_time();
|
||||
metrics->mMetricsFields[ProcessCycles] = arm_read_pmreg(ARM_PMCCNTR);
|
||||
}
|
||||
|
||||
void EndProfiling(IOPAUDIO_METRICS* metrics)
|
||||
{
|
||||
uint32_t evt0, evt1, cycles;
|
||||
arm_write_pmreg(ARM_PMCNTENCLR, ~0); /* disable all counters */
|
||||
utime_t timeEnd = system_time();
|
||||
arm_write_pmreg(ARM_PMSELR, 0);
|
||||
evt0 = arm_read_pmreg(ARM_PMXEVCNTR); /* read event 0 */
|
||||
arm_write_pmreg(ARM_PMSELR, 1);
|
||||
evt1 = arm_read_pmreg(ARM_PMXEVCNTR); /* read event 1 */
|
||||
cycles = arm_read_pmreg(ARM_PMCCNTR); /* read cycles */
|
||||
|
||||
if (arm_read_pmreg(ARM_PMOVSR))
|
||||
dprintf(DEBUG_CRITICAL, "*** counter overflow ***\n");
|
||||
|
||||
uint32_t i = ICacheAccesses;
|
||||
// choose the event monitor to follow. We only choose the first two we find
|
||||
for (;i < ACLKCycles; ++i)
|
||||
{
|
||||
if (metrics->mMetricsItemsValid & (1 << i))
|
||||
{
|
||||
metrics->mMetricsFields[i] = evt0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
for (;i < ACLKCycles; ++i)
|
||||
{
|
||||
if (metrics->mMetricsItemsValid & (1 << i))
|
||||
{
|
||||
metrics->mMetricsFields[i] = evt1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (metrics->mMetricsItemsValid & (1<<ProcessTimeUSec))
|
||||
metrics->mMetricsFields[ProcessTimeUSec] = timeEnd - metrics->mMetricsFields[ProcessTimeUSec];
|
||||
if (metrics->mMetricsItemsValid & (1<<ProcessCycles))
|
||||
metrics->mMetricsFields[ProcessCycles] = cycles - metrics->mMetricsFields[ProcessCycles];
|
||||
if (metrics->mMetricsItemsValid & (1<<HeapInUsage))
|
||||
metrics->mMetricsFields[HeapInUsage] = heap_get_free_mem();
|
||||
#ifdef DO_PEAKHEAPCHECK
|
||||
if (metrics->mMetricsItemsValid & (1<<PeakHeapUsage))
|
||||
metrics->mMetricsFields[PeakHeapUsage] = heap_get_peak_mem();
|
||||
#endif // DO_PEAKHEAPCHECK
|
||||
#ifdef DO_PEAKSTACKCHECK
|
||||
if (metrics->mMetricsItemsValid & (1<<PeakStackUsage))
|
||||
metrics->mMetricsFields[PeakStackUsage] = get_stack_usage("audio");
|
||||
#endif // DO_PEAKSTACKCHECK
|
||||
|
||||
for (uint32_t i = 0; i < kPerformanceSize; ++i)
|
||||
{
|
||||
if ((ReservedStart+i) >= MetricsFieldsSize)
|
||||
break;
|
||||
if (performanceDetails[i].valid)
|
||||
{
|
||||
metrics->mMetricsFields[ReservedStart+i] = performanceDetails[i].time;
|
||||
metrics->mMetricsItemsValid |= 1<<(ReservedStart+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void PerformanceSnapShotStart(uint32_t which) {}
|
||||
void PerformanceSnapShotEnd(uint32_t which) {}
|
||||
void SetupProfiling(IOPAUDIO_METRICS* metrics) {}
|
||||
void EndProfiling(IOPAUDIO_METRICS* metrics) { metrics->mMetricsItemsValid = 0; }
|
||||
|
||||
#endif
|
||||
|
||||
static bool audio_message_process(void);
|
||||
|
||||
static int iop_audio_task(void *cfg);
|
||||
static void iop_audio_sleep(int mode);
|
||||
|
||||
IOP_FUNCTION(audio, iop_audio_task, 64*1024, AUDIO_CONTROL_CHANNEL);
|
||||
IOP_SLEEP_HOOK(audio, iop_audio_sleep);
|
||||
|
||||
static int audio_channel;
|
||||
|
||||
#define kMaxCodecs 8
|
||||
static AudioCodec sTokens[kMaxCodecs] = { NULL, };
|
||||
|
||||
// return true if registered, false if could not.
|
||||
static bool
|
||||
Register(AudioCodec audioCodec)
|
||||
{
|
||||
for (size_t i = 0; i < kMaxCodecs; ++i)
|
||||
if (!sTokens[i])
|
||||
{
|
||||
sTokens[i] = audioCodec;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
Unregister(AudioCodec audioCodec)
|
||||
{
|
||||
for (size_t i = 0; i < kMaxCodecs; ++i)
|
||||
if (sTokens[i] == audioCodec)
|
||||
sTokens[i] = NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
isAudioCodecValid(AudioCodec audioCodec)
|
||||
{
|
||||
for (size_t i = 0; i < kMaxCodecs; ++i)
|
||||
if (sTokens[i] == audioCodec)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
iop_audio_task(void *cfg)
|
||||
{
|
||||
struct iop_channel_config *channel = (struct iop_channel_config *)cfg;
|
||||
struct task_event* audio_message_event = (struct task_event*) malloc(sizeof(struct task_event));
|
||||
|
||||
dprintf(DEBUG_SPEW, "@@ Audio task starting\n");
|
||||
|
||||
check(kIOPAUDIO_COMMAND_SIZE == sizeof(IOPAUDIO_Command));
|
||||
|
||||
/* establish the host communications channel */
|
||||
event_init(audio_message_event, EVENT_FLAG_AUTO_UNSIGNAL, false);
|
||||
dprintf(DEBUG_SPEW, "** opening audio channel\n");
|
||||
audio_channel = qwi_instantiate_channel("audio command",
|
||||
QWI_ROLE_CONSUMER,
|
||||
channel->ring_size,
|
||||
(void *)mem_static_map_cached(channel->ring_base),
|
||||
(qwi_channel_hook)event_signal,
|
||||
audio_message_event);
|
||||
|
||||
#if WITH_VFP && !WITH_VFP_ALWAYS_ON
|
||||
/* Little doubt we'll need VFP/Neon */
|
||||
arch_task_fp_enable(true);
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
dprintf(DEBUG_SPEW, "@@ waiting for message on audio channel\n");
|
||||
while (audio_message_process()) {
|
||||
// eat all available messages
|
||||
}
|
||||
event_wait(audio_message_event);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static bool
|
||||
audio_message_process(void)
|
||||
{
|
||||
uint32_t message;
|
||||
IOPAUDIO_Command* command;
|
||||
|
||||
dprintf(DEBUG_SPEW, "@@ handling host message\n");
|
||||
|
||||
/* look to see if there's an item waiting for us */
|
||||
if (qwi_receive_item(audio_channel, &message) == -1)
|
||||
return(false);
|
||||
|
||||
// set the clocks high
|
||||
SetClockState(kClockRequestMessageProcess, kClockValueHigh);
|
||||
|
||||
dprintf(DEBUG_SPEW, "@@ received audio message\n");
|
||||
|
||||
/* find the command structure based on the message */
|
||||
command = (IOPAUDIO_Command*)mem_static_map_cached(message);
|
||||
|
||||
/*
|
||||
* Flush any cached item contents we might have lying around - we are guaranteed
|
||||
* that the command size is a multiple of our cacheline size.
|
||||
*/
|
||||
platform_cache_operation(CACHE_INVALIDATE,
|
||||
(void *)command,
|
||||
sizeof(*command));
|
||||
|
||||
/*
|
||||
* TODO: make this part of the API and push this
|
||||
* architecture-specific command handling down into the s5l8920x
|
||||
* platform directory.
|
||||
*/
|
||||
switch (command->iopaudio.mOpcode) {
|
||||
|
||||
case kIOPAUDIO_OPCODE_CREATE:
|
||||
{
|
||||
AudioComponent comp = NULL;
|
||||
AudioComponentDescription desc;
|
||||
desc.componentType = command->create.mComponentDesc.mComponentType;
|
||||
desc.componentSubType = command->create.mComponentDesc.mComponentSubType;
|
||||
desc.componentManufacturer = command->create.mComponentDesc.mComponentManufacturer;
|
||||
desc.componentFlags = command->create.mComponentDesc.mComponentFlags;
|
||||
desc.componentFlagsMask = command->create.mComponentDesc.mComponentFlagsMask;
|
||||
comp = AudioComponentFindNext(comp, &desc);
|
||||
if(comp == NULL)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Could not find AudioComponent\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_CODECERROR;
|
||||
break;
|
||||
}
|
||||
dprintf(DEBUG_CRITICAL, "found component\n");
|
||||
AudioCodec audioCodec = NULL;
|
||||
size_t err = AudioComponentInstanceNew(comp, &audioCodec);
|
||||
command->iopaudio.Codec.mCodecStatus = err;
|
||||
if (err != 0 || audioCodec == NULL)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Could not create audioCodec\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_CODECERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
const void *magicCookie = (command->create.mAdditionalParametersSizeBytes) ? command->create.mAdditionalParameters : 0;
|
||||
|
||||
err = AudioCodecInitialize(audioCodec, &(command->create.mInputFormat), &(command->create.mOutputFormat), magicCookie, command->create.mAdditionalParametersSizeBytes);
|
||||
command->iopaudio.Codec.mCodecStatus = err;
|
||||
if (err != 0)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Could not initialize audioCodec\n");
|
||||
AudioComponentInstanceDispose(audioCodec);
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_CODECERROR;
|
||||
break;
|
||||
}
|
||||
if (!Register(audioCodec))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Could not register audioCodec\n");
|
||||
AudioComponentInstanceDispose(audioCodec);
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_CODECERROR;
|
||||
break;
|
||||
}
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_SUCCESS;
|
||||
command->iopaudio.Codec.mIOPToken = (uint32_t)audioCodec;
|
||||
dprintf(DEBUG_CRITICAL, "Created codec with id %x\n", command->iopaudio.Codec.mIOPToken);
|
||||
}
|
||||
break;
|
||||
case kIOPAUDIO_OPCODE_DESTROY:
|
||||
{
|
||||
AudioCodec audioCodec = (AudioCodec)command->iopaudio.Codec.mIOPToken;
|
||||
if (!isAudioCodecValid(audioCodec))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Codec not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
AudioComponentInstanceDispose(audioCodec);
|
||||
Unregister(audioCodec);
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case kIOPAUDIO_OPCODE_RESET:
|
||||
{
|
||||
AudioCodec audioCodec = (AudioCodec)command->iopaudio.Codec.mIOPToken;
|
||||
if (!isAudioCodecValid(audioCodec))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Codec not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
size_t err = AudioCodecReset(audioCodec);
|
||||
command->iopaudio.Codec.mCodecStatus = err;
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case kIOPAUDIO_OPCODE_GETPROPINFO:
|
||||
{
|
||||
AudioCodec audioCodec = (AudioCodec)command->iopaudio.Codec.mIOPToken;
|
||||
if (isAudioCodecValid(audioCodec))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Codec not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
size_t err = AudioCodecGetPropertyInfo(audioCodec, command->get_propinfo.mPropertyID, (size_t*)&command->get_propinfo.mPropertySize, (bool*)&command->get_propinfo.mPropertyWritable);
|
||||
command->iopaudio.Codec.mCodecStatus = err;
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case kIOPAUDIO_OPCODE_GETPROPERTY:
|
||||
{
|
||||
AudioCodec audioCodec = (AudioCodec)command->iopaudio.Codec.mIOPToken;
|
||||
if (isAudioCodecValid(audioCodec))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Codec not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
// <rdar://problem/8466788> update getProperty and setProperty to limit property address
|
||||
size_t max_size_for_property = sizeof(*command) - ((uint32_t)&command->get_property.mPropertyData - (uint32_t)command);
|
||||
if (max_size_for_property < command->get_property.mPropertySizeBytes)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Parameters not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
// the message should be cleaned before and after we use it, so do not need to clean ourselves
|
||||
void* property = (void*)command->get_property.mPropertyData;
|
||||
|
||||
size_t err = AudioCodecGetProperty(audioCodec, command->get_property.mPropertyID, (size_t*)&command->get_property.mPropertySizeBytes, property);
|
||||
command->iopaudio.Codec.mCodecStatus = err;
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case kIOPAUDIO_OPCODE_SETPROPERTY:
|
||||
{
|
||||
AudioCodec audioCodec = (AudioCodec)command->iopaudio.Codec.mIOPToken;
|
||||
if (isAudioCodecValid(audioCodec))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Codec not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
// <rdar://problem/8466788> update getProperty and setProperty to limit property address
|
||||
size_t max_size_for_property = sizeof(*command) - ((uint32_t)&command->get_property.mPropertyData - (uint32_t)command);
|
||||
if (max_size_for_property < command->get_property.mPropertySizeBytes)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Parameters not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
// the message should be cleaned before and after we use it, so do not need to clean ourselves
|
||||
void* property = (void*)command->get_property.mPropertyData;
|
||||
|
||||
size_t err = AudioCodecSetProperty(audioCodec, command->set_property.mPropertyID, command->set_property.mPropertySizeBytes, property);
|
||||
command->iopaudio.Codec.mCodecStatus = err;
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case kIOPAUDIO_OPCODE_PROCESSFRAME:
|
||||
{
|
||||
AudioCodec audioCodec = (AudioCodec)command->iopaudio.Codec.mIOPToken;
|
||||
if (!isAudioCodecValid(audioCodec))
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Codec not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
// <rdar://problem/8486723> function_audio should make sure parameters to processSingleFrame (input, output buffers) are valid
|
||||
// make sure the parameters are not-null.
|
||||
if (!command->process_frame.mSrcAddr
|
||||
|| !command->process_frame.mSrcSizeBytes
|
||||
|| !command->process_frame.mDstAddr
|
||||
|| !command->process_frame.mDstSizeBytes)
|
||||
{
|
||||
dprintf(DEBUG_CRITICAL, "Parameters not valid\n");
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
const void* src = (const void*)mem_static_map_cached(command->process_frame.mSrcAddr);
|
||||
void* dst = (void*)mem_static_map_cached(command->process_frame.mDstAddr);
|
||||
|
||||
|
||||
// the onus is on the caller to make sure the cache is aligned
|
||||
void* lineBase = (void*)((uint32_t)src & ~(CPU_CACHELINE_SIZE-1));
|
||||
size_t sizeToClean = ((((uint32_t)src & (CPU_CACHELINE_SIZE-1)) + command->process_frame.mSrcSizeBytes)/CPU_CACHELINE_SIZE + 1) * CPU_CACHELINE_SIZE;
|
||||
platform_cache_operation(CACHE_CLEAN | CACHE_INVALIDATE, lineBase, sizeToClean);
|
||||
|
||||
SetupProfiling(&command->process_frame.mMetrics);
|
||||
|
||||
void* packet_dst = dst;
|
||||
uint16_t numPackets = command->process_frame.mNumPackets;
|
||||
size_t remaining_dst_size = command->process_frame.mDstSizeBytes;
|
||||
size_t total_dst_size = 0;
|
||||
size_t total_src_size = 0;
|
||||
|
||||
//sanity check, if the multi frame fields are not used
|
||||
if(0 == numPackets)
|
||||
{
|
||||
numPackets = 1;
|
||||
command->process_frame.mPacketSize[0] = command->process_frame.mSrcSizeBytes;
|
||||
}
|
||||
|
||||
for(uint16_t i = 0; i < numPackets; ++i)
|
||||
{
|
||||
size_t src_size = command->process_frame.mPacketSize[i];
|
||||
//make sure we dont go pass all of the valid input data
|
||||
if(total_src_size + src_size > command->process_frame.mSrcSizeBytes)
|
||||
break;
|
||||
size_t packet_dst_size = remaining_dst_size; //the current mp3 decoder doesn't take dst size that's bigger than the packet output size
|
||||
dprintf(DEBUG_SPEW, "IOP_Audio start %d of %d, input %p size %zu, output %p, size %zu\n", i+1, numPackets, src, src_size, packet_dst, packet_dst_size);
|
||||
size_t err = AudioCodecProcessSinglePacket(audioCodec, src, &src_size, packet_dst, &packet_dst_size);
|
||||
command->iopaudio.Codec.mCodecStatus = err;
|
||||
if(err)
|
||||
break;
|
||||
packet_dst += packet_dst_size;
|
||||
remaining_dst_size -= packet_dst_size;
|
||||
total_dst_size += packet_dst_size;
|
||||
src += src_size;
|
||||
total_src_size += src_size;
|
||||
|
||||
//for encoding, write the size back to the msg
|
||||
command->process_frame.mPacketSize[i] = packet_dst_size;
|
||||
}
|
||||
command->process_frame.mSrcSizeBytes = total_src_size;
|
||||
command->process_frame.mDstSizeBytes = total_dst_size;
|
||||
|
||||
|
||||
//dprintf(DEBUG_CRITICAL, "Decoded/Encoded Total SrcSize %d, dstSize %d\n", command->process_frame.mSrcSizeBytes, command->process_frame.mDstSizeBytes);
|
||||
EndProfiling(&command->process_frame.mMetrics);
|
||||
|
||||
// the onus is on the caller to make sure the cache is aligned
|
||||
lineBase = (void*)((uint32_t)dst & ~(CPU_CACHELINE_SIZE-1));
|
||||
sizeToClean = ((((uint32_t)dst & (CPU_CACHELINE_SIZE-1)) + command->process_frame.mDstSizeBytes)/CPU_CACHELINE_SIZE + 1) * CPU_CACHELINE_SIZE;
|
||||
platform_cache_operation(CACHE_CLEAN, lineBase, sizeToClean);
|
||||
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_SUCCESS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dprintf(DEBUG_CRITICAL, "@@ ERROR: unrecognised audio opcode 0x%x\n",
|
||||
command->iopaudio.mOpcode);
|
||||
command->iopaudio.mStatus = kIOPAUDIO_STATUS_PARAM_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf(DEBUG_SPEW, "@@ done processing audio message with status 0x%08x\n", command->iopaudio.mStatus);
|
||||
|
||||
platform_cache_operation(CACHE_CLEAN,
|
||||
(void *)command,
|
||||
sizeof(IOPAUDIO_Command));
|
||||
|
||||
qwi_send_item(audio_channel, message);
|
||||
|
||||
dprintf(DEBUG_SPEW, "@@ signaled completion of audio message to host\n");
|
||||
|
||||
// set the clocks low
|
||||
SetClockState(kClockRequestMessageProcess, kClockValueLow);
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
static void
|
||||
iop_audio_sleep(int mode)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#ifndef _IOP_AUDIO_PROTOCOL_H_
|
||||
#define _IOP_AUDIO_PROTOCOL_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/*
|
||||
* Command size is (somewhat) tunable.
|
||||
*
|
||||
* The principal consideration here is the maximum scatter/gather list size
|
||||
* this permits.
|
||||
*/
|
||||
#define kIOPAUDIO_COMMAND_SIZE (512)
|
||||
|
||||
|
||||
/*
|
||||
* IOPAUDIO_opcode_t: identifies the command sent and from the AE2
|
||||
*/
|
||||
typedef uint32_t IOPAUDIO_opcode_t;
|
||||
|
||||
#define kIOPAUDIO_OPCODE_UNKNOWN ((IOPAUDIO_opcode_t) 0)
|
||||
|
||||
/*
|
||||
* Commands for communicating with AudioCodecs library
|
||||
*/
|
||||
#define kIOPAUDIO_OPCODE_CREATE ((IOPAUDIO_opcode_t) 3)
|
||||
#define kIOPAUDIO_OPCODE_DESTROY ((IOPAUDIO_opcode_t) 4)
|
||||
#define kIOPAUDIO_OPCODE_RESET ((IOPAUDIO_opcode_t) 5)
|
||||
#define kIOPAUDIO_OPCODE_PROCESSFRAME ((IOPAUDIO_opcode_t) 6)
|
||||
#define kIOPAUDIO_OPCODE_GETPROPINFO ((IOPAUDIO_opcode_t) 7)
|
||||
#define kIOPAUDIO_OPCODE_GETPROPERTY ((IOPAUDIO_opcode_t) 8)
|
||||
#define kIOPAUDIO_OPCODE_SETPROPERTY ((IOPAUDIO_opcode_t) 9)
|
||||
|
||||
/*
|
||||
* IOPAUDIO_status_t: result from commands
|
||||
*/
|
||||
typedef uint32_t IOPAUDIO_status_t;
|
||||
|
||||
#define kIOPAUDIO_STATUS_UNKNOWN ((IOPAUDIO_status_t) 0)
|
||||
#define kIOPAUDIO_STATUS_SUCCESS ((IOPAUDIO_status_t) 1)
|
||||
#define kIOPAUDIO_STATUS_FAILURE ((IOPAUDIO_status_t) 0x80000000)
|
||||
#define kIOPAUDIO_STATUS_DEVICE_ERROR ((IOPAUDIO_status_t) 0x80000001)
|
||||
#define kIOPAUDIO_STATUS_DEVICE_TIMEOUT ((IOPAUDIO_status_t) 0x80000002)
|
||||
#define kIOPAUDIO_STATUS_DMA_TIMEOUT ((IOPAUDIO_status_t) 0x80000003)
|
||||
#define kIOPAUDIO_STATUS_PARAM_INVALID ((IOPAUDIO_status_t) 0x80000004)
|
||||
#define kIOPAUDIO_STATUS_UNIMPLEMENTED ((IOPAUDIO_status_t) 0x80000005)
|
||||
#define kIOPAUDIO_STATUS_CODECERROR ((IOPAUDIO_status_t) 0x80000010)
|
||||
|
||||
|
||||
/*
|
||||
* IOPAUDIO_token_t: The opaque token to use for audio processing
|
||||
*/
|
||||
typedef uint32_t IOPAUDIO_token_t;
|
||||
typedef uint32_t IOPAUDIO_codecstatus_t;
|
||||
|
||||
/*
|
||||
* IOPAUDIO_CODEC contains the pair of token and codec status
|
||||
*/
|
||||
struct _IOPAUDIO_CODEC
|
||||
{
|
||||
IOPAUDIO_token_t mIOPToken;
|
||||
IOPAUDIO_codecstatus_t mCodecStatus;
|
||||
};
|
||||
typedef struct _IOPAUDIO_CODEC IOPAUDIO_CODEC;
|
||||
|
||||
// Token for sending messages to the iop_audio system itself
|
||||
#define kIOPAUDIO_system_token_t ((IOPAUDIO_opcode_t) 0xFFFFFFFF)
|
||||
|
||||
/*
|
||||
* IOPAUDIO_status_t result from commands
|
||||
*/
|
||||
struct _IOPAUDIO
|
||||
{
|
||||
IOPAUDIO_opcode_t mOpcode;
|
||||
IOPAUDIO_status_t mStatus;
|
||||
IOPAUDIO_CODEC Codec;
|
||||
};
|
||||
typedef struct _IOPAUDIO IOPAUDIO;
|
||||
|
||||
struct _FunctionAudioAudioComponentDescription
|
||||
{
|
||||
uint32_t mComponentType;
|
||||
uint32_t mComponentSubType;
|
||||
uint32_t mComponentManufacturer;
|
||||
uint32_t mComponentFlags;
|
||||
uint32_t mComponentFlagsMask;
|
||||
};
|
||||
typedef struct _FunctionAudioAudioComponentDescription FunctionAudioAudioComponentDescription;
|
||||
|
||||
struct _FunctionAudioAudioStreamBasicDescription
|
||||
{
|
||||
uint64_t mSampleRate;
|
||||
uint32_t mFormatID;
|
||||
uint32_t mFormatFlags;
|
||||
uint32_t mBytesPerPacket;
|
||||
uint32_t mFramesPerPacket;
|
||||
uint32_t mBytesPerFrame;
|
||||
uint32_t mChannelsPerFrame;
|
||||
uint32_t mBitsPerChannel;
|
||||
uint32_t mReserved;
|
||||
};
|
||||
typedef struct _FunctionAudioAudioStreamBasicDescription FunctionAudioAudioStreamBasicDescription;
|
||||
|
||||
enum MetricsFields
|
||||
{
|
||||
ProcessTimeUSec = 0,
|
||||
ProcessCycles,
|
||||
PeakStackUsage,
|
||||
HeapInUsage,
|
||||
PeakHeapUsage,
|
||||
ICacheAccesses, // these are measured by A5 performance monitors
|
||||
ICacheMisses,
|
||||
DCacheAccesses,
|
||||
DCacheMisses,
|
||||
Loads,
|
||||
Stores,
|
||||
UnalignedLoadStores,
|
||||
InstructionsExecuted,
|
||||
CorrectPredictedBranches,
|
||||
IncorrectPredictedBranches,
|
||||
ACLKCycles, // these are measured by AE2 performance monitors
|
||||
ACLKCyclesInWFI,
|
||||
SRAMBytesRead,
|
||||
SRAMBytesWrite,
|
||||
SRAMBytesReadWrite,
|
||||
DRAMBytesRead,
|
||||
DRAMBytesWrite,
|
||||
DRAMBytesReadWrite,
|
||||
ReservedStart,
|
||||
MetricsFieldsSize = 32
|
||||
};
|
||||
|
||||
struct _IOPAUDIO_METRICS
|
||||
{
|
||||
uint32_t mMetricsItemsValid; // bitmap marking which values are valid
|
||||
uint32_t mMetricsFields[MetricsFieldsSize];
|
||||
};
|
||||
typedef struct _IOPAUDIO_METRICS IOPAUDIO_METRICS;
|
||||
|
||||
/*
|
||||
* Messages. Message layout is dependent on the opcode. For instance, if
|
||||
* the opcode is kIOPAUDIO_OPCODE_CREATE, then the message will be interpreted
|
||||
* as IOPAUDIO_CREATE.
|
||||
* It is the senders responsiblity to make sure a message is set correctly.
|
||||
*/
|
||||
|
||||
/*
|
||||
* IOPAUDIO_CREATE message
|
||||
* Message used to create a new audio process.
|
||||
* If message succeeds, iopToken will contain the token used for processing.
|
||||
* Fill the input and output with necessary parameters. Additional parameters
|
||||
* passed through the additional_paramters pointer.
|
||||
*
|
||||
* It is decoder specific how additional data is laid out.
|
||||
*/
|
||||
struct _IOPAUDIO_CREATE
|
||||
{
|
||||
IOPAUDIO mIOPHeader;
|
||||
|
||||
FunctionAudioAudioComponentDescription mComponentDesc;
|
||||
FunctionAudioAudioStreamBasicDescription mInputFormat;
|
||||
FunctionAudioAudioStreamBasicDescription mOutputFormat;
|
||||
uint32_t mAdditionalParametersSizeBytes;
|
||||
uint8_t mAdditionalParameters[];
|
||||
};
|
||||
typedef struct _IOPAUDIO_CREATE IOPAUDIO_CREATE;
|
||||
|
||||
/*
|
||||
* IOPAUDIO_DESTROY message
|
||||
* Message used to destroy a token.
|
||||
* If message succeeds, iopToken is no longer valid.
|
||||
*/
|
||||
struct _IOPAUDIO_DESTROY
|
||||
{
|
||||
IOPAUDIO mIOPHeader;
|
||||
};
|
||||
typedef struct _IOPAUDIO_DESTROY IOPAUDIO_DESTROY;
|
||||
|
||||
/*
|
||||
* IOPAUDIO_RESET message
|
||||
* Message used to reset an audio process
|
||||
* If message succeeds, iopToken is reset to the starting state.
|
||||
*/
|
||||
struct _IOPAUDIO_RESET
|
||||
{
|
||||
IOPAUDIO mIOPHeader;
|
||||
};
|
||||
typedef struct _IOPAUDIO_RESET IOPAUDIO_RESET;
|
||||
|
||||
/*
|
||||
* IOPAUDIO_GETPROPINFO message
|
||||
* Message used to get property information. mPropertyID is the 4-char code
|
||||
* indicating what property to get info on.
|
||||
* If message succeeds, size and writablility are set.
|
||||
*/
|
||||
struct _IOPAUDIO_GETPROPINFO
|
||||
{
|
||||
IOPAUDIO mIOPHeader;
|
||||
|
||||
uint32_t mPropertyID;
|
||||
uint32_t mPropertySize;
|
||||
uint32_t mPropertyWritable;
|
||||
};
|
||||
typedef struct _IOPAUDIO_GETPROPINFO IOPAUDIO_GETPROPINFO;
|
||||
|
||||
/*
|
||||
* IOPAUDIO_GETPROPERTY message
|
||||
* Message used to get property. mPropertyID is the 4-char code indicating what
|
||||
* property to get.
|
||||
* Addr passed in is the physical address where should be written. It can
|
||||
* point within the message or point to some other buffer that IOP can access.
|
||||
* If message succeeds, the property is written to the Addr.
|
||||
*/
|
||||
struct _IOPAUDIO_GETPROPERTY
|
||||
{
|
||||
IOPAUDIO mIOPHeader;
|
||||
|
||||
uint32_t mPropertyID;
|
||||
uint32_t mPropertySizeBytes;
|
||||
uint8_t mPropertyData[];
|
||||
};
|
||||
typedef struct _IOPAUDIO_GETPROPERTY IOPAUDIO_GETPROPERTY;
|
||||
|
||||
/*
|
||||
* IOPAUDIO_SETPROPERTY message
|
||||
* Message used to set property. mPropertyID is the 4-char code indicating what
|
||||
* property to set.
|
||||
* Addr passed in is the physical address which has the data to write. It can
|
||||
* point within the message or point to some other buffer that IOP can access.
|
||||
* If message succeeds, the property is written to the Addr.
|
||||
*/
|
||||
struct _IOPAUDIO_SETPROPERTY
|
||||
{
|
||||
IOPAUDIO mIOPHeader;
|
||||
|
||||
uint32_t mPropertyID;
|
||||
uint32_t mPropertySizeBytes;
|
||||
uint8_t mPropertyData[];
|
||||
};
|
||||
typedef struct _IOPAUDIO_SETPROPERTY IOPAUDIO_SETPROPERTY;
|
||||
|
||||
/*
|
||||
* IOPAUDIO_PROCESSFRAME message
|
||||
* Process audio from the src_addr to the dst_addr. On input, src_size is
|
||||
* the size of the source data, dst_size is the size available to write into.
|
||||
* On output, src_size is the amount of data consumed, dst_size is the amount
|
||||
* of data written.
|
||||
* Metrics may or may not be filled in, depending on the build.
|
||||
*/
|
||||
struct _IOPAUDIO_PROCESSFRAME
|
||||
{
|
||||
IOPAUDIO mIOPHeader;
|
||||
|
||||
uint32_t mSrcAddr;
|
||||
uint32_t mDstAddr;
|
||||
uint32_t mSrcSizeBytes;
|
||||
uint32_t mDstSizeBytes;
|
||||
IOPAUDIO_METRICS mMetrics;
|
||||
//add packet information for multple packets
|
||||
uint16_t mNumPackets;
|
||||
uint16_t mPacketSize[];
|
||||
};
|
||||
typedef struct _IOPAUDIO_PROCESSFRAME IOPAUDIO_PROCESSFRAME;
|
||||
|
||||
union _IOPAUDIO_Command
|
||||
{
|
||||
IOPAUDIO iopaudio;
|
||||
|
||||
IOPAUDIO_CREATE create;
|
||||
IOPAUDIO_DESTROY destroy;
|
||||
IOPAUDIO_RESET reset;
|
||||
IOPAUDIO_PROCESSFRAME process_frame;
|
||||
IOPAUDIO_GETPROPINFO get_propinfo;
|
||||
IOPAUDIO_GETPROPERTY get_property;
|
||||
IOPAUDIO_SETPROPERTY set_property;
|
||||
|
||||
uint8_t _pad[kIOPAUDIO_COMMAND_SIZE];
|
||||
};
|
||||
typedef union _IOPAUDIO_Command IOPAUDIO_Command;
|
||||
|
||||
|
||||
#endif // _IOP_AUDIO_PROTOCOL_H_
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Computer, Inc.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Empty namespace std stubs
|
||||
*/
|
||||
namespace std
|
||||
{
|
||||
void __throw_bad_alloc()
|
||||
{}
|
||||
|
||||
void __throw_length_error(char const*)
|
||||
{}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (C) 2010 Apple Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Inc.
|
||||
#
|
||||
|
||||
#
|
||||
# Audio driver
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += WITH_FUNCTION_AUDIO=1
|
||||
IOP_FUNCTIONS += AUDIO
|
||||
|
||||
ALL_OBJS += $(LOCAL_DIR)/iop_audio.o \
|
||||
$(LOCAL_DIR)/libstd_stub.o
|
||||
|
||||
INSTALL_HEADERS += $(LOCAL_DIR)/iop_audio_protocol.h
|
||||
|
||||
# We need 64 k for stack
|
||||
# and 372064 for heap
|
||||
# 192512 of which will be in SRAM
|
||||
export IOP_HEAP_REQUIRED := $(call ADD,$(IOP_HEAP_REQUIRED),245088)
|
||||
|
||||
GLOBAL_INCLUDES += $(SDKROOT)/usr/local/standalone/firmware \
|
||||
$(SDKROOT)/usr/local/standalone/firmware/include \
|
||||
# $(SDKROOT)/../../../usr/local/standalone/firmware/Accelerate.framework/Frameworks/vecLib.framework/Headers
|
||||
|
||||
PREBUILT_STATICLIBS += $(SDKROOT)/usr/local/standalone/firmware/libm.a \
|
||||
$(SDKROOT)/usr/local/standalone/firmware/libvDSP.a \
|
||||
$(SDKROOT)/usr/local/standalone/firmware/libAudioCodecsA5.a
|
||||
Reference in new issue
Block a user