Home | History | Annotate | Download | only in android
      1 /*
      2 **
      3 ** Copyright 2008, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 //#define LOG_NDEBUG 0
     19 #define LOG_TAG "AudioMIO"
     20 #include <utils/Log.h>
     21 
     22 #include "android_audio_mio.h"
     23 #include "pvlogger.h"
     24 #include "pv_mime_string_utils.h"
     25 #include "oscl_snprintf.h"
     26 #include "oscl_mem.h"
     27 #include "oscl_dll.h"
     28 #include "oscl_mem.h"
     29 
     30 #include <sys/prctl.h>
     31 
     32 #include <utils/Timers.h>
     33 #include <sys/resource.h>
     34 #include <limits.h>
     35 
     36 #include <utils/threads.h>
     37 
     38 #include <media/AudioTrack.h>
     39 
     40 using namespace android;
     41 
     42 // depth of buffer/command queues in MIO
     43 static const int kCommandQueueDepth = 10;
     44 
     45 // Define entry point for this DLL
     46 OSCL_DLL_ENTRY_POINT_DEFAULT()
     47 
     48 // Audio Media IO component base class implementation
     49 OSCL_EXPORT_REF AndroidAudioMIO::AndroidAudioMIO(const char* name)
     50     : OsclTimerObject(OsclActiveObject::EPriorityNominal, name),
     51     iWriteCompleteAO(NULL)
     52 {
     53     initData();
     54 }
     55 
     56 OSCL_EXPORT_REF AndroidAudioMIO::~AndroidAudioMIO()
     57 {
     58     LOGV("destructor");
     59     Cleanup();
     60 }
     61 
     62 void AndroidAudioMIO::initData()
     63 {
     64     LOGV("initData in");
     65     ResetData();
     66 
     67     iCommandCounter = 0;
     68     iLogger = NULL;
     69     iCommandResponseQueue.reserve(kCommandQueueDepth);
     70     iWriteResponseQueueLock.Create();
     71     iWriteResponseQueue.reserve(kCommandQueueDepth);
     72     iObserver = NULL;
     73     iLogger = NULL;
     74     iPeer = NULL;
     75     iState = STATE_MIO_IDLE;
     76     iWriteBusy = false;
     77     iFlushPending = false;
     78     iDataQueued = 0;
     79     LOGV("initData out");
     80 }
     81 
     82 void AndroidAudioMIO::ResetData()
     83 //reset all data from this session.
     84 {
     85     LOGV("ResetData in");
     86     // reset all the received media parameters.
     87     iAudioFormat = PVMF_MIME_FORMAT_UNKNOWN;
     88     iAudioNumChannelsValid = false;
     89     iAudioSamplingRateValid = false;
     90     iAudioThreadCreatedAndMIOConfigured = false;
     91     LOGV("ResetData out");
     92 }
     93 
     94 //cleanup all allocated memory and release resources.
     95 void AndroidAudioMIO::Cleanup()
     96 {
     97     LOGV("Cleanup in");
     98     while (!iCommandResponseQueue.empty()) {
     99         if (iObserver) {
    100             iObserver->RequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId,
    101                         iCommandResponseQueue[0].iContext, iCommandResponseQueue[0].iStatus));
    102         }
    103         iCommandResponseQueue.erase(&iCommandResponseQueue[0]);
    104     }
    105 
    106     // return empty buffers
    107     returnAllBuffers();
    108 
    109     // delete the request active object
    110     if (iWriteCompleteAO) {
    111         OSCL_DELETE(iWriteCompleteAO);
    112         iWriteCompleteAO = NULL;
    113     }
    114     iWriteResponseQueueLock.Close();
    115     LOGV("Cleanup out");
    116 }
    117 
    118 PVMFStatus AndroidAudioMIO::connect(PvmiMIOSession& aSession, PvmiMIOObserver* aObserver)
    119 {
    120     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::connect() called"));
    121 
    122     // currently supports only one session
    123     if (iObserver) return PVMFFailure;
    124     iObserver = aObserver;
    125     return PVMFSuccess;
    126 }
    127 
    128 PVMFStatus AndroidAudioMIO::disconnect(PvmiMIOSession aSession)
    129 {
    130     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::disconnect() called"));
    131     iObserver = NULL;
    132     return PVMFSuccess;
    133 }
    134 
    135 
    136 PvmiMediaTransfer* AndroidAudioMIO::createMediaTransfer(PvmiMIOSession& aSession,
    137                             PvmiKvp* read_formats, int32 read_flags,
    138                             PvmiKvp* write_formats, int32 write_flags)
    139 {
    140     // create the request active object
    141     // such when audio output thread is done with a buffer
    142     // it can put the buffer on the write response queue
    143     // and schedule this MIO to run, to return the buffer
    144     // to the engine
    145     iWriteCompleteAO = OSCL_NEW(AndroidAudioOutputThreadSafeCallbackAO,(this, 5));
    146 
    147     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::createMediaTransfer() called"));
    148     return (PvmiMediaTransfer*)this;
    149 }
    150 
    151 PVMFCommandId AndroidAudioMIO::QueueCmdResponse(PVMFStatus status, const OsclAny* aContext)
    152 {
    153     PVMFCommandId cmdId = iCommandCounter++;
    154     CommandResponse resp(status, cmdId, aContext);
    155     iCommandResponseQueue.push_back(resp);
    156 
    157     // cancel any timer delay so the command response will happen ASAP.
    158     if (IsBusy()) Cancel();
    159     RunIfNotReady();
    160     return cmdId;
    161 }
    162 
    163 // return any held buffers to the engine
    164 void AndroidAudioMIO::ProcessWriteResponseQueue()
    165 {
    166     //LOGV("ProcessWriteResponseQueue in [Response Q size %d]",iWriteResponseQueue.size());
    167     PVMFStatus status = 0;
    168     PVMFCommandId cmdId = 0;
    169     const OsclAny* context = 0;
    170 
    171     iWriteResponseQueueLock.Lock();
    172     while (!iWriteResponseQueue.empty()) {
    173         status = iWriteResponseQueue[0].iStatus;
    174         cmdId = iWriteResponseQueue[0].iCmdId;
    175         context = (OsclAny*)iWriteResponseQueue[0].iContext;
    176         iWriteResponseQueue.erase(&iWriteResponseQueue[0]);
    177         iWriteResponseQueueLock.Unlock();
    178         if (iPeer) {
    179             LOGV("Return buffer(%d) status(%d) context(%p)", cmdId,status,context);
    180             iPeer->writeComplete(status, cmdId, (OsclAny*)context);
    181         }
    182         iWriteResponseQueueLock.Lock();
    183     }
    184     iWriteResponseQueueLock.Unlock();
    185     //LOGV("ProcessWriteResponseQueue out");
    186 }
    187 
    188 PVMFCommandId AndroidAudioMIO::QueryUUID(const PvmfMimeString& aMimeType,
    189                                         Oscl_Vector<PVUuid, OsclMemAllocator>& aUuids,
    190                                         bool aExactUuidsOnly, const OsclAny* aContext)
    191 {
    192     LOGV("QueryUUID");
    193     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::QueryUUID() called"));
    194     return QueueCmdResponse(PVMFFailure, aContext);
    195 }
    196 
    197 PVMFCommandId AndroidAudioMIO::QueryInterface(const PVUuid& aUuid, PVInterface*& aInterfacePtr, const OsclAny* aContext)
    198 {
    199     LOGV("QueryInterface");
    200     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::QueryInterface() called"));
    201     PVMFStatus status=PVMFFailure;
    202     if (aUuid == PVMI_CAPABILITY_AND_CONFIG_PVUUID) {
    203         PvmiCapabilityAndConfig* myInterface = OSCL_STATIC_CAST(PvmiCapabilityAndConfig*, this);
    204         aInterfacePtr = OSCL_STATIC_CAST(PVInterface*, myInterface);
    205         status = PVMFSuccess;
    206     }
    207     return QueueCmdResponse(status, aContext);
    208 }
    209 
    210 PVMFCommandId AndroidAudioMIO::Init(const OsclAny* aContext)
    211 {
    212     LOGV("Init (%p)", aContext);
    213     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::Init() called"));
    214     iState=STATE_MIO_INITIALIZED;
    215     return QueueCmdResponse(PVMFSuccess, aContext);
    216 }
    217 
    218 PVMFCommandId AndroidAudioMIO::Reset(const OsclAny* aContext)
    219 {
    220     LOGV("Reset (%p)", aContext);
    221     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::Reset() called"));
    222     return QueueCmdResponse(PVMFSuccess, aContext);
    223 }
    224 
    225 PVMFCommandId AndroidAudioMIO::Start(const OsclAny* aContext)
    226 {
    227     // Start is NO-OP
    228     LOGV("Start (%p)", aContext);
    229     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::Start() called"));
    230     iState = STATE_MIO_STARTED;
    231     return QueueCmdResponse(PVMFSuccess, aContext);
    232 }
    233 
    234 PVMFCommandId AndroidAudioMIO::Pause(const OsclAny* aContext)
    235 {
    236     LOGV("Pause (%p)", aContext);
    237     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::Pause() called"));
    238     iState = STATE_MIO_PAUSED;
    239     return QueueCmdResponse(PVMFSuccess, aContext);
    240 }
    241 
    242 
    243 PVMFCommandId AndroidAudioMIO::Flush(const OsclAny* aContext)
    244 {
    245     LOGV("Flush (%p)", aContext);
    246     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::Flush() called"));
    247     iState = STATE_MIO_INITIALIZED;
    248     return QueueCmdResponse(PVMFSuccess, aContext);
    249 }
    250 
    251 PVMFCommandId AndroidAudioMIO::DiscardData(const OsclAny* aContext)
    252 {
    253     LOGV("DiscardData (%p)", aContext);
    254     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::DiscardData() called"));
    255     return DiscardData(UINT_MAX, aContext);
    256 }
    257 
    258 PVMFCommandId AndroidAudioMIO::DiscardData(PVMFTimestamp aTimestamp, const OsclAny* aContext)
    259 {
    260     LOGV("DiscardData (%u, %p)", aTimestamp, aContext);
    261     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::DiscardData() called"));
    262     return QueueCmdResponse(PVMFSuccess, aContext);
    263 }
    264 
    265 PVMFCommandId AndroidAudioMIO::Stop(const OsclAny* aContext)
    266 {
    267     LOGV("Stop (%p)", aContext);
    268     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::Stop() called"));
    269     iState = STATE_MIO_INITIALIZED;
    270     return QueueCmdResponse(PVMFSuccess, aContext);
    271 }
    272 
    273 PVMFCommandId AndroidAudioMIO::CancelAllCommands(const OsclAny* aContext)
    274 {
    275     LOGV("CancelAllCommands (%p)", aContext);
    276     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::CancelAllCommands() called"));
    277 
    278     //commands are executed immediately upon being received, so
    279     //it isn't really possible to cancel them.
    280     return QueueCmdResponse(PVMFSuccess, aContext);
    281 }
    282 
    283 PVMFCommandId AndroidAudioMIO::CancelCommand(PVMFCommandId aCmdId, const OsclAny* aContext)
    284 {
    285     LOGV("CancelCommand (%u, %p)", aCmdId, aContext);
    286     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::CancelCommand() called"));
    287 
    288     //see if the response is still queued.
    289     PVMFStatus status = PVMFFailure;
    290     for (uint32 i = 0; i < iCommandResponseQueue.size(); i++) {
    291         if (iCommandResponseQueue[i].iCmdId == aCmdId) {
    292             status = PVMFSuccess;
    293             break;
    294         }
    295     }
    296     return QueueCmdResponse(PVMFSuccess, aContext);
    297 }
    298 
    299 void AndroidAudioMIO::ThreadLogon()
    300 {
    301     LOGV("ThreadLogon() called ");
    302     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::ThreadLogon() called"));
    303     if (iState == STATE_MIO_IDLE) {
    304         iLogger = PVLogger::GetLoggerObject("AndroidAudioMIO\n");
    305         AddToScheduler();
    306         iState=STATE_MIO_LOGGED_ON;
    307     }
    308 }
    309 
    310 void AndroidAudioMIO::ThreadLogoff()
    311 {
    312     LOGV("ThreadLogoff() called");
    313     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::ThreadLogoff() called"));
    314     if (iState!=STATE_MIO_IDLE) {
    315         RemoveFromScheduler();
    316         iLogger = NULL;
    317         iState = STATE_MIO_IDLE;
    318         ResetData();
    319     }
    320 }
    321 
    322 void AndroidAudioMIO::setPeer(PvmiMediaTransfer* aPeer)
    323 {
    324     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE, (0,"AndroidAudioMIO::setPeer() called"));
    325     // Set the observer
    326     iPeer = aPeer;
    327 }
    328 
    329 //This routine will determine whether data can be accepted in a writeAsync
    330 //call and if not, will return true;
    331 bool AndroidAudioMIO::CheckWriteBusy(uint32 aSeqNum)
    332 {
    333     // FIXME: this line screws up video output - why?
    334     // return (iOSSRequestQueue.size() >= 5);
    335     return false;
    336 }
    337 
    338 PVMFCommandId AndroidAudioMIO::writeAsync(uint8 aFormatType, int32 aFormatIndex, uint8* aData, uint32 aDataLen,
    339                                         const PvmiMediaXferHeader& data_header_info, OsclAny* aContext)
    340 {
    341     // Do a leave if MIO is not configured except when it is an EOS
    342     if (!iAudioThreadCreatedAndMIOConfigured
    343             &&
    344             !((PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION == aFormatType)
    345               && (PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM == aFormatIndex)))
    346     {
    347         LOGE("ERROR :: data is pumped in before mio configured");
    348         OSCL_LEAVE(OsclErrInvalidState);
    349         return -1;
    350     }
    351 
    352     uint32 aSeqNum = data_header_info.seq_num;
    353     PVMFTimestamp aTimestamp = data_header_info.timestamp;
    354     uint32 flags = data_header_info.flags;
    355 
    356     bool bWriteComplete = true;
    357 
    358     //LOGV("writeAsync() called seqnum %d ts %d flags %d context %d formattype %d formatindex %d",aSeqNum, aTimestamp, flags,aContext,aFormatType,aFormatIndex);
    359     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    360         (0,"AndroidAudioMIO::writeAsync() seqnum %d ts %d flags %d context %d",
    361          aSeqNum, aTimestamp, flags,aContext));
    362 
    363     PVMFStatus status=PVMFFailure;
    364 
    365     switch(aFormatType) {
    366     case PVMI_MEDIAXFER_FMT_TYPE_COMMAND :
    367         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    368             (0,"AndroidAudioMIO::writeAsync() called with Command info."));
    369         //ignore
    370         LOGV("PVMI_MEDIAXFER_FMT_TYPE_COMMAND");
    371         status = PVMFSuccess;
    372         break;
    373 
    374     case PVMI_MEDIAXFER_FMT_TYPE_NOTIFICATION :
    375         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    376             (0,"AndroidAudioMIO::writeAsync() called with Notification info."));
    377         switch(aFormatIndex) {
    378         case PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM:
    379             LOGV("PVMI_MEDIAXFER_FMT_INDEX_END_OF_STREAM");
    380             bWriteComplete = false; //force an empty buffer through the audio thread
    381             break;
    382         default:
    383             break;
    384         }
    385         //ignore
    386         status = PVMFSuccess;
    387         break;
    388 
    389     case PVMI_MEDIAXFER_FMT_TYPE_DATA :
    390         switch(aFormatIndex) {
    391         case PVMI_MEDIAXFER_FMT_INDEX_FMT_SPECIFIC_INFO:
    392             status = PVMFSuccess;
    393             LOGV("PVMI_MEDIAXFER_FMT_INDEX_FMT_SPECIFIC_INFO");
    394             break;
    395 
    396         case PVMI_MEDIAXFER_FMT_INDEX_DATA:
    397             LOGV("PVMI_MEDIAXFER_FMT_INDEX_DATA");
    398             //data contains the media bitstream.
    399 
    400             //Check whether we can accept data now and leave if we can't.
    401             if (CheckWriteBusy(aSeqNum)) {
    402                 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
    403                     (0,"AndroidAudioMIO::writeAsync: Entering busy state"));
    404 
    405                 //schedule an event to re-start the data flow.
    406                 iWriteBusy = true;
    407                 bWriteComplete = false;
    408 
    409                 // Rich:: commenting in this line.
    410                 //        Need some timeout here just in case.
    411                 //        I have no evidence of any problems.
    412                 RunIfNotReady(10 * 1000);
    413                 OSCL_LEAVE(OsclErrBusy);
    414             } else {
    415                 if (aDataLen > 0) {
    416                     // this buffer will be queued by the audio output thread to process
    417                     // this buffer cannot be write completed until
    418                     // it has been processed by the audio output thread
    419                     bWriteComplete = false;
    420                 } else {
    421                        LOGE("writeAsync() called with aDataLen==0");
    422                        PVLOGGER_LOGMSG(PVLOGMSG_INST_HLDBG, iLogger, PVLOGMSG_INFO,
    423                             (0,"AndroidAudioMIO::writeAsync() called aDataLen==0."));
    424                 }
    425                 status = PVMFSuccess;
    426             }
    427             break;
    428 
    429         default:
    430             LOGE("Error unrecognized format index =%u", aFormatIndex);
    431             PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
    432                 (0,"AndroidAudioMIO::writeAsync: Error - unrecognized format index"));
    433             status = PVMFFailure;
    434             break;
    435         }
    436         break;
    437 
    438     default:
    439         LOGE("Error unrecognized format type =%u", aFormatType);
    440         PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, iLogger, PVLOGMSG_ERR,
    441             (0,"AndroidAudioMIO::writeAsync: Error - unrecognized format type"));
    442         status = PVMFFailure;
    443         break;
    444     }
    445 
    446     //Schedule asynchronous response
    447     PVMFCommandId cmdid=iCommandCounter++;
    448     if (bWriteComplete) {
    449         LOGV("write complete (%d)", cmdid);
    450         WriteResponse resp(status, cmdid, aContext, aTimestamp);
    451         iWriteResponseQueueLock.Lock();
    452         iWriteResponseQueue.push_back(resp);
    453         iWriteResponseQueueLock.Unlock();
    454         RunIfNotReady();
    455     } else if (!iWriteBusy) {
    456         writeAudioBuffer(aData, aDataLen, cmdid, aContext, aTimestamp);
    457     }
    458     LOGV("data queued = %u", iDataQueued);
    459 
    460     return cmdid;
    461 }
    462 
    463 PVMFStatus AndroidAudioMIO::getParametersSync(PvmiMIOSession aSession, PvmiKeyType aIdentifier,
    464                                               PvmiKvp*& aParameters, int& num_parameter_elements,
    465                                               PvmiCapabilityContext aContext)
    466 {
    467     LOGV("getParametersSync in %s",aIdentifier);
    468     OSCL_UNUSED_ARG(aSession);
    469     OSCL_UNUSED_ARG(aContext);
    470     aParameters=NULL;
    471     num_parameter_elements=0;
    472     PVMFStatus status = PVMFFailure;
    473 
    474     if(pv_mime_strcmp(aIdentifier, INPUT_FORMATS_CAP_QUERY) == 0) {
    475         //This is a query for the list of supported formats.
    476         aParameters=(PvmiKvp*)oscl_malloc(2 * sizeof(PvmiKvp));
    477         if (aParameters) {
    478             aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_PCM16;
    479             aParameters[num_parameter_elements++].value.pChar_value = (char*)PVMF_MIME_PCM8;
    480             status = PVMFSuccess;
    481         }
    482         else{
    483             status = PVMFErrNoMemory;
    484         }
    485     }
    486     //other queries are not currently supported.
    487 
    488     //unrecognized key.
    489     LOGV("getParametersSync out status %d",status);
    490     return status;
    491 }
    492 
    493 PVMFStatus AndroidAudioMIO::releaseParameters(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
    494 {
    495     LOGV("releaseParameters in");
    496     OSCL_UNUSED_ARG(aSession);
    497     OSCL_UNUSED_ARG(num_elements);
    498     PVMFStatus status = PVMFFailure;
    499     //release parameters that were allocated by this component.
    500     if (aParameters) {
    501         oscl_free(aParameters);
    502         status = PVMFSuccess;
    503     }
    504     LOGV("releaseParameters out status %d",status);
    505     return status;
    506 }
    507 
    508 PVMFStatus AndroidAudioMIO::verifyParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters, int num_elements)
    509 {
    510     OSCL_UNUSED_ARG(aSession);
    511     //LOGV("verifyParametersSync in");
    512 
    513     // Go through each parameter
    514     for (int32 i=0; i<num_elements; i++) {
    515         char* compstr = NULL;
    516         pv_mime_string_extract_type(0, aParameters[i].key, compstr);
    517         if (pv_mime_strcmp(compstr, _STRLIT_CHAR("x-pvmf/media/format-type")) == 0) {
    518             if ((pv_mime_strcmp(aParameters[i].value.pChar_value, PVMF_MIME_PCM8) == 0) ||
    519                 (pv_mime_strcmp(aParameters[i].value.pChar_value, PVMF_MIME_PCM16) == 0)
    520                ) {
    521                 return PVMFSuccess;
    522             }
    523             else {
    524                 return PVMFErrNotSupported;
    525             }
    526         }
    527     }
    528     return PVMFSuccess;
    529     //LOGV("verifyParametersSync out");
    530 
    531 }
    532 void AndroidAudioMIO::setParametersSync(PvmiMIOSession aSession, PvmiKvp* aParameters,
    533                                         int num_elements, PvmiKvp * & aRet_kvp)
    534 {
    535     OSCL_UNUSED_ARG(aSession);
    536     //LOGV("setParametersSync in");
    537     aRet_kvp = NULL;
    538 
    539     for (int32 i=0;i<num_elements;i++) {
    540         //Check against known audio parameter keys...
    541         if (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_FORMAT_KEY) == 0) {
    542             LOGV("Audio format: %s", aParameters[i].value.pChar_value);
    543             iAudioFormat=aParameters[i].value.pChar_value;
    544             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    545                 (0,"AndroidAudioOutput::setParametersSync() Audio Format Key, Value %s",aParameters[i].value.pChar_value));
    546         } else if (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_SAMPLING_RATE_KEY) == 0) {
    547             iAudioSamplingRate=(int32)aParameters[i].value.uint32_value;
    548             iAudioSamplingRateValid=true;
    549             // LOGD("iAudioSamplingRate=%d", iAudioSamplingRate);
    550             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    551                 (0,"AndroidAudioMIO::setParametersSync() Audio Sampling Rate Key, Value %d",iAudioSamplingRate));
    552         } else if (pv_mime_strcmp(aParameters[i].key, MOUT_AUDIO_NUM_CHANNELS_KEY) == 0) {
    553             iAudioNumChannels=(int32)aParameters[i].value.uint32_value;
    554             iAudioNumChannelsValid=true;
    555             // LOGD("iAudioNumChannels=%d", iAudioNumChannels);
    556             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    557                 (0,"AndroidAudioMIO::setParametersSync() Audio Num Channels Key, Value %d",iAudioNumChannels));
    558         } else {
    559             //if we get here the key is unrecognized.
    560             PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_STACK_TRACE,
    561                 (0,"AndroidAudioMIO::setParametersSync() Error, unrecognized key %s",aParameters[i].key));
    562 
    563             //set the return value to indicate the unrecognized key
    564             //and return.
    565             aRet_kvp = &aParameters[i];
    566             return;
    567         }
    568     }
    569 
    570     //LOGV("setParametersSync out");
    571 }
    572 
    573 //
    574 // Private section
    575 //
    576 
    577 void AndroidAudioMIO::Run()
    578 {
    579     while (!iCommandResponseQueue.empty()) {
    580         if (iObserver) {
    581             iObserver->RequestCompleted(PVMFCmdResp(iCommandResponseQueue[0].iCmdId,
    582                         iCommandResponseQueue[0].iContext,
    583                         iCommandResponseQueue[0].iStatus));
    584         }
    585         iCommandResponseQueue.erase(&iCommandResponseQueue[0]);
    586     }
    587 
    588     //send async write completion
    589     ProcessWriteResponseQueue();
    590 
    591     //Re-start the data transfer if needed.
    592     if (iWriteBusy) {
    593         iWriteBusy = false;
    594         iPeer->statusUpdate(PVMI_MEDIAXFER_STATUS_WRITE);
    595     }
    596 }
    597 
    598 // send response to MIO
    599 void AndroidAudioMIO::sendResponse(PVMFCommandId cmdid, const OsclAny* context, PVMFTimestamp timestamp)
    600 {
    601     LOGV("sendResponse :: return buffer (%d) timestamp(%d) context(%p)", cmdid, timestamp, context);
    602     WriteResponse resp(PVMFSuccess, cmdid, context, timestamp);
    603     iWriteResponseQueueLock.Lock();
    604     if (iWriteResponseQueue.size() < iWriteResponseQueue.capacity()) {
    605         iWriteResponseQueue.push_back(resp);
    606     } else {
    607         LOGE("Exceeded response queue capacity");
    608     }
    609     iWriteResponseQueueLock.Unlock();
    610 
    611     // Create an event for the threadsafe callback AO
    612     OsclAny* P = NULL;
    613     iWriteCompleteAO->ReceiveEvent(P);
    614 }
    615 
    616 void AndroidAudioMIO::setAudioSink(const sp<MediaPlayerInterface::AudioSink>& audioSink)
    617 {
    618     LOGV("setAudioSink in");
    619     mAudioSink = audioSink;
    620 }
    621 
    622 //------------------------------------------------------------------------
    623 // Active timing support
    624 //
    625 OSCL_EXPORT_REF PVMFStatus AndroidAudioMIOActiveTimingSupport::SetClock(PVMFMediaClock *clockVal)
    626 {
    627     LOGV("ATS :: SetClock in");
    628     iClock=clockVal;
    629 
    630     return PVMFSuccess;
    631 }
    632 
    633 void AndroidAudioMIOActiveTimingSupport::NotificationsInterfaceDestroyed()
    634 {
    635     LOGV("ATS :: NotificationsInterfaceDestroyed in");
    636     iClockNotificationsInf=NULL;
    637 }
    638 
    639 
    640 OSCL_EXPORT_REF bool AndroidAudioMIOActiveTimingSupport::queryInterface(const PVUuid& aUuid, PVInterface*& aInterface)
    641 {
    642     aInterface = NULL;
    643     PVUuid uuid;
    644     queryUuid(uuid);
    645     bool status = false;
    646     if (uuid == aUuid) {
    647         PvmiClockExtensionInterface* myInterface = OSCL_STATIC_CAST(PvmiClockExtensionInterface*, this);
    648         aInterface = OSCL_STATIC_CAST(PVInterface*, myInterface);
    649         status = true;
    650     }
    651     LOGV("ATS :: queryInterface out status %d",status);
    652     return status;
    653 }
    654 
    655 void AndroidAudioMIOActiveTimingSupport::queryUuid(PVUuid& uuid)
    656 {
    657     LOGV("ATS :: queryUuid in");
    658     uuid = PvmiClockExtensionInterfaceUuid;
    659 }
    660 
    661 void AndroidAudioMIOActiveTimingSupport::ClockStateUpdated()
    662 {
    663     LOGV("ATS :: ClockStateUpdated in");
    664     if (iClock) {
    665 
    666         PVMFMediaClock::PVMFMediaClockState newClockState = iClock->GetState();
    667         if (newClockState != iClockState) {
    668             iClockState = newClockState;
    669             switch (iClockState) {
    670             case PVMFMediaClock::STOPPED:
    671                 LOGV("A/V clock stopped");
    672                 break;
    673             case PVMFMediaClock::RUNNING:
    674                 LOGV("A/V clock running");
    675                 // must be seeking, get new clock offset for A/V sync
    676                 if (iUpdateClock) {
    677                     bool overflowFlag = false;
    678                     uint32 currentTimeBase32 = 0;
    679                     iClock->GetCurrentTime32(iStartTime, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, currentTimeBase32);
    680                     iFrameCount = 0;
    681                     iUpdateClock = false;
    682                     LOGV("update iStartTime: %d", iStartTime);
    683                 }
    684                 LOGV("signal thread to start");
    685                 if (iAudioThreadSem) iAudioThreadSem->Signal();
    686                 break;
    687             case PVMFMediaClock::PAUSED:
    688                 LOGV("A/V clock paused");
    689                 break;
    690             default:
    691                 LOGE("Wrong clock state!");
    692                 break;
    693             }
    694         }
    695     }
    696     LOGV("ATS :: ClockStateUpdated out");
    697 }
    698 
    699 void AndroidAudioMIOActiveTimingSupport::UpdateClock()
    700 {
    701     LOGV("ATS :: UpdateClock in");
    702     if (iClock && (iClockState == PVMFMediaClock::RUNNING)) {
    703         uint32 clockTime32, timeBaseTime32, updateClock32;
    704         int32 correction = 0;
    705         bool overflowFlag = false;
    706         // get current time
    707         iClock->GetCurrentTime32(clockTime32, overflowFlag, PVMF_MEDIA_CLOCK_MSEC, timeBaseTime32);
    708         LOGV("PV clock current = %u", clockTime32);
    709 
    710         // calculate sample clock
    711         updateClock32 = iFrameCount * iMsecsPerFrame;
    712         LOGV("sample clock = %u frameCount(%u) msecsPerFrame(%f)", updateClock32,iFrameCount,iMsecsPerFrame);
    713 
    714         correction = updateClock32 - (clockTime32 - iStartTime);
    715         LOGV("ADJ_CLK iDriverLatency %d old clock %d delta %d", iDriverLatency, clockTime32, correction);
    716 
    717         // do clock correction if drift exceeds threshold
    718         if (OSCL_ABS(correction) > iMinCorrection) {
    719             if (correction > iMaxCorrection) {
    720                 correction = iMaxCorrection;
    721             } else if (correction < -iMaxCorrection) {
    722                 correction = -iMaxCorrection;
    723             }
    724             updateClock32 = clockTime32 + correction;
    725             LOGV("ADJ_CLK old clock %d correction %d new clock %d", clockTime32, correction, updateClock32);
    726 
    727             PVMFMediaClockAdjustTimeStatus adjustmentstatus =
    728             iClock->AdjustClockTime32(clockTime32, timeBaseTime32, updateClock32,PVMF_MEDIA_CLOCK_MSEC,overflowFlag);
    729 
    730             if ((PVMF_MEDIA_CLOCK_ADJUST_SUCCESS != adjustmentstatus))
    731             {
    732                 LOGE("Error adjusting clock status = %d",adjustmentstatus);
    733             }
    734             if(overflowFlag) {
    735             LOGE("Adjusting clock caused overflow");
    736             }
    737         }
    738         else{
    739             LOGV("ATS :: sample clock and pv clock are close enough no need to update");
    740         }
    741     }
    742     LOGV("ATS :: UpdateClock out");
    743 }
    744 void AndroidAudioMIOActiveTimingSupport::setDriverLatency(uint32 latency)
    745 {
    746     LOGV("ATS :: setDriverLatency in");
    747     iDriverLatency = latency;
    748     if (iClock){
    749         LOGV("register latency to media clock and set clockobserver");
    750         PVMFStatus ret = iClock->ConstructMediaClockNotificationsInterface(iClockNotificationsInf,*this,latency);
    751         if(iClockNotificationsInf && (PVMFSuccess == ret))
    752         {
    753             iClockNotificationsInf->SetClockStateObserver(*this);
    754         }
    755         else
    756         {
    757             LOGE("latency could NOT be set !! set it later ");
    758         }
    759     }
    760     LOGV("ATS :: setDriverLatency out");
    761 }
    762 
    763