/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <errno.h> #include <utils/StrongPointer.h> #include "Log.h" #include "audio/Buffer.h" #include "StringUtil.h" #include "SimpleScriptExec.h" #include "SignalProcessingImpl.h" #include "task/TaskCase.h" enum ToPythonCommandType { EHeader = 0x0, ETerminate = 0x1, EFunctionName = 0x2, EAudioMono = 0x4, EAudioStereo = 0x5, EValue64Int = 0x8, EValueDouble = 0x9, EExecutionResult = 0x10 }; const android::String8 \ SignalProcessingImpl::MAIN_PROCESSING_SCRIPT("test_description/processing_main.py"); SignalProcessingImpl::SignalProcessingImpl() : mChildRunning(false), mBuffer(1024) { } SignalProcessingImpl::~SignalProcessingImpl() { if (mSocket.get() != NULL) { int terminationCommand [] = {ETerminate, 0}; send((char*)terminationCommand, sizeof(terminationCommand)); mSocket->release(); } if (mChildRunning) { waitpid(mChildPid, NULL, 0); } } #define CHILD_LOGE(x...) do { fprintf(stderr, x); \ fprintf(stderr, " %s - %d\n", __FILE__, __LINE__); } while(0) const int CHILD_WAIT_TIME_US = 100000; bool SignalProcessingImpl::init(const android::String8& script) { pid_t pid; if ((pid = fork()) < 0) { LOGE("SignalProcessingImpl::init fork failed %d", errno); return false; } else if (pid == 0) { // child if (execl(SimpleScriptExec::PYTHON_PATH, SimpleScriptExec::PYTHON_PATH, script.string(), NULL) < 0) { CHILD_LOGE("execl %s %s failed %d", SimpleScriptExec::PYTHON_PATH, script.string(), errno); exit(EXIT_FAILURE); } } else { // parent mChildPid = pid; mChildRunning = true; int result = false; int retryCount = 0; // not that clean, but it takes some time for python side to have socket ready const int MAX_RETRY = 20; while (retryCount < MAX_RETRY) { usleep(CHILD_WAIT_TIME_US); mSocket.reset(new ClientSocket()); if (mSocket.get() == NULL) { result = false; break; } if (mSocket->init("127.0.0.1", SCRIPT_PORT, true)) { result = true; break; } retryCount++; } if (!result) { LOGE("cannot connect to child"); mSocket.reset(NULL); return result; } } return true; } TaskGeneric::ExecutionResult SignalProcessingImpl::run( const android::String8& functionScript, int nInputs, bool* inputTypes, void** inputs, int nOutputs, bool* outputTypes, void** outputs) { mBuffer.reset(); mBuffer.write <int32_t>((int32_t)EHeader); mBuffer.write<int32_t>(nInputs + 1); mBuffer.write<int32_t>((int32_t)EFunctionName); mBuffer.write<int32_t>((int32_t)functionScript.length()); mBuffer.writeStr(functionScript); if (!send(mBuffer.getBuffer(), mBuffer.getSizeWritten())) { LOGE("send failed"); return TaskGeneric::EResultError; } for (int i = 0; i < nInputs; i++) { mBuffer.reset(); if (inputTypes[i]) { // android::sp<Buffer>* android::sp<Buffer>* buffer = reinterpret_cast<android::sp<Buffer>*>(inputs[i]); mBuffer.write<int32_t>((int32_t)((*buffer)->isStereo() ? EAudioStereo : EAudioMono)); int dataLen = (*buffer)->getSize(); mBuffer.write<int32_t>(dataLen); if (!send(mBuffer.getBuffer(), mBuffer.getSizeWritten())) { LOGE("send failed"); return TaskGeneric::EResultError; } if (!send((*buffer)->getData(), dataLen)) { LOGE("send failed"); return TaskGeneric::EResultError; } LOGD("%d-th param buffer %d, stereo:%d", dataLen, (*buffer)->isStereo()); } else { //TaskCase::Value* TaskCase::Value* val = reinterpret_cast<TaskCase::Value*>(inputs[i]); bool isI64 = (val->getType() == TaskCase::Value::ETypeI64); mBuffer.write<int32_t>((int32_t)(isI64 ? EValue64Int : EValueDouble)); if (isI64) { mBuffer.write<int64_t>(val->getInt64()); } else { mBuffer.write<double>(val->getDouble()); } if (!send(mBuffer.getBuffer(), mBuffer.getSizeWritten())) { LOGE("send failed"); return TaskGeneric::EResultError; } LOGD("%d-th param Value", i); } } int32_t header[4]; // id 0 - no of types - id 0x10 - ExecutionResult if (!read((char*)header, sizeof(header))) { LOGE("read failed"); return TaskGeneric::EResultError; } if (header[0] != 0) { LOGE("wrong data"); return TaskGeneric::EResultError; } if (header[2] != EExecutionResult) { LOGE("wrong data"); return TaskGeneric::EResultError; } if (header[3] == TaskGeneric::EResultError) { LOGE("script returned error %d", header[3]); return (TaskGeneric::ExecutionResult)header[3]; } if ((header[1] - 1) != nOutputs) { LOGE("wrong data"); return TaskGeneric::EResultError; } for (int i = 0; i < nOutputs; i++) { int32_t type; if (!read((char*)&type, sizeof(type))) { LOGE("read failed"); return TaskGeneric::EResultError; } if (outputTypes[i]) { // android::sp<Buffer>* int32_t dataLen; if (!read((char*)&dataLen, sizeof(dataLen))) { LOGE("read failed"); return TaskGeneric::EResultError; } android::sp<Buffer>* buffer = reinterpret_cast<android::sp<Buffer>*>(outputs[i]); if (buffer->get() == NULL) { // data not allocated, this can happen for unknown-length output *buffer = new Buffer(dataLen, dataLen, (type == EAudioStereo) ? true: false); if (buffer->get() == NULL) { LOGE("alloc failed"); return TaskGeneric::EResultError; } } bool isStereo = (*buffer)->isStereo(); if (((type == EAudioStereo) && isStereo) || ((type == EAudioMono) && !isStereo)) { // valid } else { LOGE("%d-th output wrong type %d stereo: %d", i, type, isStereo); return TaskGeneric::EResultError; } if (dataLen > (int)(*buffer)->getSize()) { LOGE("%d-th output data too long %d while buffer size %d", i, dataLen, (*buffer)->getSize()); return TaskGeneric::EResultError; } if (!read((*buffer)->getData(), dataLen)) { LOGE("read failed"); return TaskGeneric::EResultError; } LOGD("received buffer %x %x", ((*buffer)->getData())[0], ((*buffer)->getData())[1]); (*buffer)->setHandled(dataLen); (*buffer)->setSize(dataLen); } else { //TaskCase::Value* TaskCase::Value* val = reinterpret_cast<TaskCase::Value*>(outputs[i]); if ((type == EValue64Int) || (type == EValueDouble)) { if (!read((char*)val->getPtr(), sizeof(int64_t))) { LOGE("read failed"); return TaskGeneric::EResultError; } if (type == EValue64Int) { val->setType(TaskCase::Value::ETypeI64); } else { val->setType(TaskCase::Value::ETypeDouble); } } else { LOGE("wrong type %d", type); return TaskGeneric::EResultError; } } } return (TaskGeneric::ExecutionResult)header[3]; } bool SignalProcessingImpl::send(const char* data, int len) { //LOGD("send %d", len); return mSocket->sendData(data, len); } bool SignalProcessingImpl::read(char* data, int len) { const int READ_TIMEOUT_MS = 60000 * 2; // as some calculation like calc_delay takes almost 20 secs //LOGD("read %d", len); return mSocket->readData(data, len, READ_TIMEOUT_MS); }