int MPLSensor::readEvents(sensors_event_t* data, int count) { //VFUNC_LOG; int i; bool irq_set[5] = { false, false, false, false, false }; inv_error_t rv; if (count < 1) return -EINVAL; int numEventReceived = 0; clearIrqData(irq_set); pthread_mutex_lock(&mMplMutex); if (mDmpStarted) { //ALOGV_IF(EXTRA_VERBOSE, "Update Data"); rv = inv_update_data(); ALOGE_IF(rv != INV_SUCCESS, "inv_update_data error (code %d)", (int) rv); } else { //probably just one extra read after shutting down ALOGV_IF(EXTRA_VERBOSE, "MPLSensor::readEvents called, but there's nothing to do."); } pthread_mutex_unlock(&mMplMutex); if (!mNewData) { ALOGV_IF(EXTRA_VERBOSE, "no new data"); return 0; } mNewData = 0; /* google timestamp */ pthread_mutex_lock(&mMplMutex); for (int i = 0; i < numSensors; i++) { if (mEnabled & (1 << i)) { CALL_MEMBER_FN(this,mHandlers[i])(mPendingEvents + i, &mPendingMask, i); mPendingEvents[i].timestamp = irq_timestamp; } } for (int j = 0; count && mPendingMask && j < numSensors; j++) { if (mPendingMask & (1 << j)) { mPendingMask &= ~(1 << j); if (mEnabled & (1 << j)) { *data++ = mPendingEvents[j]; count--; numEventReceived++; } } } pthread_mutex_unlock(&mMplMutex); return numEventReceived; }
status_t MediaPlayer::setParameter(int key, const Parcel& request) { ALOGV("MediaPlayer::setParameter(%d)", key); status_t status = INVALID_OPERATION; Mutex::Autolock _l(mLock); if (checkStateForKeySet_l(key) != OK) { return status; } switch (key) { case KEY_PARAMETER_AUDIO_ATTRIBUTES: // save the marshalled audio attributes if (mAudioAttributesParcel != NULL) { delete mAudioAttributesParcel; }; mAudioAttributesParcel = new Parcel(); mAudioAttributesParcel->appendFrom(&request, 0, request.dataSize()); status = OK; break; default: ALOGV_IF(mPlayer == NULL, "setParameter: no active player"); break; } if (mPlayer != NULL) { status = mPlayer->setParameter(key, request); } return status; }
static int out_standby_stream_locked(struct astream_out *out) { int ret = 0; int attempts = MAX_WRITE_COMPLETION_ATTEMPTS; if (out->standby || !out->data) return 0; out->standby = true; /* wait for write completion if needed */ while (out->write_busy && attempts--) { ret = pthread_cond_timeout_np(&out->write_cond, &out->lock, BUF_WRITE_COMPLETION_TIMEOUT_MS); ALOGE_IF(ret != 0, "out_standby_stream_locked() wait cond error %d", ret); } ALOGE_IF(attempts == 0, "out_standby_stream_locked() a2dp_write() would not stop!!!"); ALOGV_IF(!out->bt_enabled, "Standby skip stop: enabled %d", out->bt_enabled); if (out->bt_enabled) { ret = a2dp_stop(out->data); } release_wake_lock(A2DP_WAKE_LOCK_NAME); return ret; }
audio_io_handle_t AudioSystem::getOutput(audio_stream_type_t stream, uint32_t samplingRate, uint32_t format, uint32_t channels, audio_policy_output_flags_t flags) { audio_io_handle_t output = 0; // Do not use stream to output map cache if the direct output // flag is set or if we are likely to use a direct output // (e.g voice call stream @ 8kHz could use BT SCO device and be routed to // a direct output on some platforms). // TODO: the output cache and stream to output mapping implementation needs to // be reworked for proper operation with direct outputs. This code is too specific // to the first use case we want to cover (Voice Recognition and Voice Dialer over // Bluetooth SCO if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) == 0 && ((stream != AUDIO_STREAM_VOICE_CALL && stream != AUDIO_STREAM_BLUETOOTH_SCO) || channels != AUDIO_CHANNEL_OUT_MONO || (samplingRate != 8000 && samplingRate != 16000))) { Mutex::Autolock _l(gLock); output = AudioSystem::gStreamOutputMap.valueFor(stream); ALOGV_IF((output != 0), "getOutput() read %d from cache for stream %d", output, stream); } if (output == 0) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return 0; output = aps->getOutput(stream, samplingRate, format, channels, flags); if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) == 0) { Mutex::Autolock _l(gLock); AudioSystem::gStreamOutputMap.add(stream, output); } } return output; }
int MPLSensor::enable(int32_t handle, int en) { FUNC_LOG; //ALOGV("handle : %d en: %d", handle, en); int what = -1; switch (handle) { case ID_A: what = Accelerometer; break; case ID_M: what = MagneticField; break; case ID_O: what = Orientation; break; case ID_GY: what = Gyro; break; case ID_GR: what = Gravity; break; case ID_RV: what = RotationVector; break; case ID_LA: what = LinearAccel; break; default: //this takes care of all the gestures what = handle; break; } if (uint32_t(what) >= numSensors) return -EINVAL; int newState = en ? 1 : 0; int err = 0; //ALOGV_IF((uint32_t(newState) << what) != (mEnabled & (1 << what)), // "sensor state change what=%d", what); pthread_mutex_lock(&mMplMutex); if ((uint32_t(newState) << what) != (mEnabled & (1 << what))) { uint32_t sensor_type; short flags = newState; mEnabled &= ~(1 << what); mEnabled |= (uint32_t(flags) << what); ALOGV_IF(EXTRA_VERBOSE, "mEnabled = %x", mEnabled); setPowerStates(mEnabled); pthread_mutex_unlock(&mMplMutex); if (!newState) update_delay(); return err; } pthread_mutex_unlock(&mMplMutex); return err; }
int MPLSensor::setDelay(int32_t handle, int64_t ns) { FUNC_LOG; ALOGV_IF(EXTRA_VERBOSE, " setDelay handle: %d rate %d", handle, (int) (ns / 1000000LL)); int what = -1; switch (handle) { case ID_A: what = Accelerometer; break; case ID_M: what = MagneticField; break; case ID_O: what = Orientation; break; case ID_GY: what = Gyro; break; case ID_GR: what = Gravity; break; case ID_RV: what = RotationVector; break; case ID_LA: what = LinearAccel; break; default: what = handle; break; } if (uint32_t(what) >= numSensors) return -EINVAL; if (ns < 0) return -EINVAL; pthread_mutex_lock(&mMplMutex); mDelays[what] = ns; pthread_mutex_unlock(&mMplMutex); return update_delay(); }
bool AudioDecoder::start() { auto oldTime = clockNow(); auto nowTime = oldTime; bool ret; do { ret = decodeToPcm(); if (!ret) { ALOGE("decodeToPcm (%s) failed!", _url.c_str()); break; } nowTime = clockNow(); ALOGD("Decoding (%s) to pcm data wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); oldTime = nowTime; ret = resample(); if (!ret) { ALOGE("resample (%s) failed!", _url.c_str()); break; } nowTime = clockNow(); ALOGD("Resampling (%s) wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); oldTime = nowTime; ret = interleave(); if (!ret) { ALOGE("interleave (%s) failed!", _url.c_str()); break; } nowTime = clockNow(); ALOGD("Interleave (%s) wasted %fms", _url.c_str(), intervalInMS(oldTime, nowTime)); } while(false); ALOGV_IF(!ret, "%s returns false, decode (%s)", __FUNCTION__, _url.c_str()); return ret; }
StatusTracker::ComponentState StatusTracker::getDeviceStateLocked() { for (size_t i = 0; i < mStates.size(); i++) { if (mStates.valueAt(i) == ACTIVE) { ALOGV("%s: Component %d not idle", __FUNCTION__, mStates.keyAt(i)); return ACTIVE; } } // - If not yet signaled, getSignalTime returns INT64_MAX // - If invalid fence or error, returns -1 // - Otherwise returns time of signalling. // Treat -1 as 'signalled', since HAL may not be using fences, and want // to be able to idle in case of errors. nsecs_t signalTime = mIdleFence->getSignalTime(); bool fencesDone = signalTime != INT64_MAX; ALOGV_IF(!fencesDone, "%s: Fences still to wait on", __FUNCTION__); return fencesDone ? IDLE : ACTIVE; }
int MPLSensor::update_delay() { FUNC_LOG; int rv = 0; bool irq_set[5]; pthread_mutex_lock(&mMplMutex); if (mEnabled) { uint64_t wanted = -1LLU; for (int i = 0; i < numSensors; i++) { if (mEnabled & (1 << i)) { uint64_t ns = mDelays[i]; wanted = wanted < ns ? wanted : ns; } } //Limit all rates to 100Hz max. 100Hz = 10ms = 10000000ns if (wanted < 10000000LLU) { wanted = 10000000LLU; } int rate = ((wanted) / 5000000LLU) - ((wanted % 5000000LLU == 0) ? 1 : 0); //mpu fifo rate is in increments of 5ms if (rate == 0) //KLP disallow fifo rate 0 rate = 1; if (rate != mCurFifoRate) { //ALOGD("set fifo rate: %d %llu", rate, wanted); inv_error_t res; // = inv_dmp_stop(); res = inv_set_fifo_rate(rate); ALOGE_IF(res != INV_SUCCESS, "error setting FIFO rate"); //res = inv_dmp_start(); //ALOGE_IF(res != INV_SUCCESS, "error re-starting DMP"); mCurFifoRate = rate; rv = (res == INV_SUCCESS); } if (((inv_get_dl_config()->requested_sensors & INV_DMP_PROCESSOR) == 0)) { if (mUseTimerirq) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_STOP, 0); clearIrqData(irq_set); if (inv_get_dl_config()->requested_sensors == INV_THREE_AXIS_COMPASS) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_START, (unsigned long) (wanted / 1000000LLU)); ALOGV_IF(EXTRA_VERBOSE, "updated timerirq period to %d", (int) (wanted / 1000000LLU)); } else { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_START, (unsigned long) inv_get_sample_step_size_ms()); ALOGV_IF(EXTRA_VERBOSE, "updated timerirq period to %d", (int) inv_get_sample_step_size_ms()); } } } } pthread_mutex_unlock(&mMplMutex); return rv; }
/* set the power states of the various sensors based on the bits set in the * enabled_sensors parameter. * this function modifies globalish state variables. It must be called with the mMplMutex held. */ void MPLSensor::setPowerStates(int enabled_sensors) { FUNC_LOG; bool irq_set[5] = { false, false, false, false, false }; //ALOGV(" setPowerStates: %d dmp_started: %d", enabled_sensors, mDmpStarted); do { if (LA_ENABLED || GR_ENABLED || RV_ENABLED || O_ENABLED) { mLocalSensorMask = ALL_MPL_SENSORS_NP; break; } if (!A_ENABLED && !M_ENABLED && !GY_ENABLED) { mLocalSensorMask = 0; break; } if (GY_ENABLED) { mLocalSensorMask |= INV_THREE_AXIS_GYRO; } else { mLocalSensorMask &= ~INV_THREE_AXIS_GYRO; } if (A_ENABLED) { mLocalSensorMask |= (INV_THREE_AXIS_ACCEL); } else { mLocalSensorMask &= ~(INV_THREE_AXIS_ACCEL); } if (M_ENABLED) { mLocalSensorMask |= INV_THREE_AXIS_COMPASS; } else { mLocalSensorMask &= ~(INV_THREE_AXIS_COMPASS); } } while (0); //record the new sensor state inv_error_t rv; long sen_mask = mLocalSensorMask & mMasterSensorMask; bool changing_sensors = ((inv_get_dl_config()->requested_sensors != sen_mask) && (sen_mask != 0)); bool restart = (!mDmpStarted) && (sen_mask != 0); if (changing_sensors || restart) { ALOGV_IF(EXTRA_VERBOSE, "cs:%d rs:%d ", changing_sensors, restart); if (mDmpStarted) { inv_dmp_stop(); clearIrqData(irq_set); mDmpStarted = false; } if (sen_mask != inv_get_dl_config()->requested_sensors) { //ALOGV("setPowerStates: %lx", sen_mask); rv = inv_set_mpu_sensors(sen_mask); ALOGE_IF(rv != INV_SUCCESS, "error: unable to set MPL sensor power states (sens=%ld retcode = %d)", sen_mask, rv); } if (((mUsetimerIrqCompass && (sen_mask == INV_THREE_AXIS_COMPASS)) || (mUseTimerIrqAccel && (sen_mask & INV_THREE_AXIS_ACCEL))) && ((sen_mask & INV_DMP_PROCESSOR) == 0)) { ALOGV_IF(EXTRA_VERBOSE, "Allowing TimerIRQ"); mUseTimerirq = true; } else { if (mUseTimerirq) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_STOP, 0); clearIrqData(irq_set); } ALOGV_IF(EXTRA_VERBOSE, "Not allowing TimerIRQ"); mUseTimerirq = false; } if (!mDmpStarted) { if (mHaveGoodMpuCal || mHaveGoodCompassCal) { rv = inv_store_calibration(); ALOGE_IF(rv != INV_SUCCESS, "error: unable to store MPL calibration file"); mHaveGoodMpuCal = false; mHaveGoodCompassCal = false; } //ALOGV("Starting DMP"); rv = inv_dmp_start(); ALOGE_IF(rv != INV_SUCCESS, "unable to start dmp"); mDmpStarted = true; } } //check if we should stop the DMP if (mDmpStarted && (sen_mask == 0)) { //ALOGV("Stopping DMP"); rv = inv_dmp_stop(); ALOGE_IF(rv != INV_SUCCESS, "error: unable to stop DMP (retcode = %d)", rv); if (mUseTimerirq) { ioctl(mIrqFds.valueFor(TIMERIRQ_FD), TIMERIRQ_STOP, 0); } clearIrqData(irq_set); mDmpStarted = false; mPollTime = -1; mCurFifoRate = -1; } }
MPLSensor::MPLSensor() : SensorBase(NULL, NULL), mNewData(0), mDmpStarted(false), mMasterSensorMask(INV_ALL_SENSORS), mLocalSensorMask(ALL_MPL_SENSORS_NP), mPollTime(-1), mCurFifoRate(-1), mHaveGoodMpuCal(false), mHaveGoodCompassCal(false), mUseTimerIrqAccel(false), mUsetimerIrqCompass(true), mUseTimerirq(false), mSampleCount(0), mEnabled(0), mPendingMask(0) { FUNC_LOG; inv_error_t rv; int mpu_int_fd, i; char *port = NULL; ALOGV_IF(EXTRA_VERBOSE, "MPLSensor constructor: numSensors = %d", numSensors); pthread_mutex_init(&mMplMutex, NULL); mForceSleep = false; /* used for identifying whether 9axis is enabled or not */ /* this variable will be changed in initMPL() when libmpl is loaded */ /* sensor list will be changed based on this variable */ mNineAxisEnabled = false; for (i = 0; i < ARRAY_SIZE(mPollFds); i++) { mPollFds[i].fd = -1; mPollFds[i].events = 0; } pthread_mutex_lock(&mMplMutex); mpu_int_fd = open("/dev/mpuirq", O_RDWR); if (mpu_int_fd == -1) { ALOGE("could not open the mpu irq device node"); } else { fcntl(mpu_int_fd, F_SETFL, O_NONBLOCK); //ioctl(mpu_int_fd, MPUIRQ_SET_TIMEOUT, 0); mIrqFds.add(MPUIRQ_FD, mpu_int_fd); mPollFds[MPUIRQ_FD].fd = mpu_int_fd; mPollFds[MPUIRQ_FD].events = POLLIN; } accel_fd = open("/dev/accelirq", O_RDWR); if (accel_fd == -1) { ALOGE("could not open the accel irq device node"); } else { fcntl(accel_fd, F_SETFL, O_NONBLOCK); //ioctl(accel_fd, SLAVEIRQ_SET_TIMEOUT, 0); mIrqFds.add(ACCELIRQ_FD, accel_fd); mPollFds[ACCELIRQ_FD].fd = accel_fd; mPollFds[ACCELIRQ_FD].events = POLLIN; } timer_fd = open("/dev/timerirq", O_RDWR); if (timer_fd == -1) { ALOGE("could not open the timer irq device node"); } else { fcntl(timer_fd, F_SETFL, O_NONBLOCK); //ioctl(timer_fd, TIMERIRQ_SET_TIMEOUT, 0); mIrqFds.add(TIMERIRQ_FD, timer_fd); mPollFds[TIMERIRQ_FD].fd = timer_fd; mPollFds[TIMERIRQ_FD].events = POLLIN; } data_fd = mpu_int_fd; if ((accel_fd == -1) && (timer_fd != -1)) { //no accel irq and timer available mUseTimerIrqAccel = true; //ALOGD("MPLSensor falling back to timerirq for accel data"); } memset(mPendingEvents, 0, sizeof(mPendingEvents)); mPendingEvents[RotationVector].version = sizeof(sensors_event_t); mPendingEvents[RotationVector].sensor = ID_RV; mPendingEvents[RotationVector].type = SENSOR_TYPE_ROTATION_VECTOR; mPendingEvents[LinearAccel].version = sizeof(sensors_event_t); mPendingEvents[LinearAccel].sensor = ID_LA; mPendingEvents[LinearAccel].type = SENSOR_TYPE_LINEAR_ACCELERATION; mPendingEvents[Gravity].version = sizeof(sensors_event_t); mPendingEvents[Gravity].sensor = ID_GR; mPendingEvents[Gravity].type = SENSOR_TYPE_GRAVITY; mPendingEvents[Gyro].version = sizeof(sensors_event_t); mPendingEvents[Gyro].sensor = ID_GY; mPendingEvents[Gyro].type = SENSOR_TYPE_GYROSCOPE; mPendingEvents[Accelerometer].version = sizeof(sensors_event_t); mPendingEvents[Accelerometer].sensor = ID_A; mPendingEvents[Accelerometer].type = SENSOR_TYPE_ACCELEROMETER; mPendingEvents[MagneticField].version = sizeof(sensors_event_t); mPendingEvents[MagneticField].sensor = ID_M; mPendingEvents[MagneticField].type = SENSOR_TYPE_MAGNETIC_FIELD; mPendingEvents[MagneticField].magnetic.status = SENSOR_STATUS_ACCURACY_HIGH; mPendingEvents[Orientation].version = sizeof(sensors_event_t); mPendingEvents[Orientation].sensor = ID_O; mPendingEvents[Orientation].type = SENSOR_TYPE_ORIENTATION; mPendingEvents[Orientation].orientation.status = SENSOR_STATUS_ACCURACY_HIGH; mHandlers[RotationVector] = &MPLSensor::rvHandler; mHandlers[LinearAccel] = &MPLSensor::laHandler; mHandlers[Gravity] = &MPLSensor::gravHandler; mHandlers[Gyro] = &MPLSensor::gyroHandler; mHandlers[Accelerometer] = &MPLSensor::accelHandler; mHandlers[MagneticField] = &MPLSensor::compassHandler; mHandlers[Orientation] = &MPLSensor::orienHandler; for (int i = 0; i < numSensors; i++) mDelays[i] = 30000000LLU; // 30 ms by default if (inv_serial_start(port) != INV_SUCCESS) { ALOGE("Fatal Error : could not open MPL serial interface"); } //initialize library parameters initMPL(); //setup the FIFO contents setupFIFO(); //we start the motion processing only when a sensor is enabled... //rv = inv_dmp_start(); //ALOGE_IF(rv != INV_SUCCESS, "Fatal error: could not start the DMP correctly. (code = %d)\n", rv); //dmp_started = true; pthread_mutex_unlock(&mMplMutex); }
void AudioMixerController::mixOneFrame() { _isMixingFrame = true; _activeTracksMutex.lock(); auto mixStart = clockNow(); std::vector<Track*> tracksToRemove; tracksToRemove.reserve(_activeTracks.size()); // FOR TESTING BEGIN // Track* track = _activeTracks[0]; // // AudioBufferProvider::Buffer buffer; // buffer.frameCount = _bufferSizeInFrames; // status_t r = track->getNextBuffer(&buffer); //// ALOG_ASSERT(buffer.frameCount == _mixing->size / 2, "buffer.frameCount:%d, _mixing->size/2:%d", buffer.frameCount, _mixing->size/2); // if (r == NO_ERROR) // { // ALOGV("getNextBuffer succeed ..."); // memcpy(_mixing->buf, buffer.raw, _mixing->size); // } // if (buffer.raw == nullptr) // { // ALOGV("Play over ..."); // tracksToRemove.push_back(track); // } // else // { // track->releaseBuffer(&buffer); // } // // _mixing->state = BufferState::FULL; // _activeTracksMutex.unlock(); // FOR TESTING END Track::State state; // set up the tracks. for (auto&& track : _activeTracks) { state = track->getState(); if (state == Track::State::IDLE) { initTrack(track, tracksToRemove); } else if (state == Track::State::PLAYING) { if (!track->isInitialized()) { initTrack(track, tracksToRemove); } int name = track->getName(); ALOG_ASSERT(name >= 0); std::lock_guard<std::mutex> lk(track->_volumeDirtyMutex); if (track->isVolumeDirty()) { gain_minifloat_packed_t volume = track->getVolumeLR(); float lVolume = float_from_gain(gain_minifloat_unpack_left(volume)); float rVolume = float_from_gain(gain_minifloat_unpack_right(volume)); ALOGV("Track (name: %d)'s volume is dirty, update volume to L: %f, R: %f", name, lVolume, rVolume); _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &lVolume); _mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &rVolume); track->setVolumeDirty(false); } } else if (state == Track::State::RESUMED) { if (!track->isInitialized()) { initTrack(track, tracksToRemove); } if (track->getPrevState() == Track::State::PAUSED) { _mixer->enable(track->getName()); track->setState(Track::State::PLAYING); } else { ALOGW("Previous state (%d) isn't PAUSED, couldn't resume!", static_cast<int>(track->getPrevState())); } } else if (state == Track::State::PAUSED) { if (!track->isInitialized()) { initTrack(track, tracksToRemove); } if (track->getPrevState() == Track::State::PLAYING || track->getPrevState() == Track::State::RESUMED) { _mixer->disable(track->getName()); } else { ALOGW("Previous state (%d) isn't PLAYING, couldn't pause!", static_cast<int>(track->getPrevState())); } } else if (state == Track::State::STOPPED) { if (track->isInitialized()) { if (track->getPrevState() != Track::State::IDLE) { _mixer->deleteTrackName(track->getName()); } else { ALOGV("Stop track (%p) while it's in IDLE state!", track); } } else { ALOGV("Track (%p) hasn't been initialized yet!", track); } tracksToRemove.push_back(track); } if (track->isPlayOver()) { if (track->isLoop()) { track->reset(); } else { ALOGV("Play over ..."); _mixer->deleteTrackName(track->getName()); tracksToRemove.push_back(track); track->setState(Track::State::OVER); } } } bool hasAvailableTracks = _activeTracks.size() - tracksToRemove.size() > 0; if (hasAvailableTracks) { ALOGV_IF(_activeTracks.size() > 8, "More than 8 active tracks: %d", (int) _activeTracks.size()); _mixer->process(AudioBufferProvider::kInvalidPTS); } else { ALOGV("Doesn't have enough tracks: %d, %d", (int) _activeTracks.size(), (int) tracksToRemove.size()); } // Remove stopped or playover tracks for active tracks container for (auto&& track : tracksToRemove) { removeItemFromVector(_activeTracks, track); if (track != nullptr && track->onStateChanged != nullptr) { track->onStateChanged(Track::State::DESTROYED); } else { ALOGE("track (%p) was released ...", track); } } _activeTracksMutex.unlock(); auto mixEnd = clockNow(); float mixInterval = intervalInMS(mixStart, mixEnd); ALOGV_IF(mixInterval > 1.0f, "Mix a frame waste: %fms", mixInterval); _isMixingFrame = false; }
void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) { ATRACE_CALL(); status_t res; Mutex::Autolock m(mMutex); // Make sure this is for the current heap ssize_t offset; size_t size; sp<IMemoryHeap> heap = mem->getMemory(&offset, &size); if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) { ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release " "(got %x, expected %x)", __FUNCTION__, mId, heap->getHeapID(), mRecordingHeap->mHeap->getHeapID()); return; } uint8_t *data = (uint8_t*)heap->getBase() + offset; uint32_t type = *(uint32_t*)data; if (type != kMetadataBufferTypeGrallocSource) { ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)", __FUNCTION__, mId, type, kMetadataBufferTypeGrallocSource); return; } // Release the buffer back to the recording queue buffer_handle_t imgHandle = *(buffer_handle_t*)(data + 4); size_t itemIndex; for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) { const BufferItemConsumer::BufferItem item = mRecordingBuffers[itemIndex]; if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT && item.mGraphicBuffer->handle == imgHandle) { break; } } if (itemIndex == mRecordingBuffers.size()) { ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of " "outstanding buffers", __FUNCTION__, mId, imgHandle); return; } ALOGVV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__, mId, imgHandle); res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]); if (res != OK) { ALOGE("%s: Camera %d: Unable to free recording frame " "(buffer_handle_t: %p): %s (%d)", __FUNCTION__, mId, imgHandle, strerror(-res), res); return; } mRecordingBuffers.replaceAt(itemIndex); mRecordingHeapFree++; ALOGV_IF(mRecordingHeapFree == mRecordingHeapCount, "%s: Camera %d: All %d recording buffers returned", __FUNCTION__, mId, mRecordingHeapCount); }