Loading audio/2.0/default/StreamOut.cpp +19 −6 Original line number Diff line number Diff line Loading @@ -164,6 +164,9 @@ StreamOut::~StreamOut() { } mCallback.clear(); mDevice->closeOutputStream(mStream); // Closing the output stream in the HAL waits for the callback to finish, // and joins the callback thread. Thus is it guaranteed that the callback // thread will not be accessing our object anymore. mStream = nullptr; } Loading Loading @@ -404,6 +407,8 @@ Return<void> StreamOut::getNextWriteTimestamp( Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; // Safe to pass 'this' because it is guaranteed that the callback thread // is joined prior to exit from StreamOut's destructor. int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); if (result == 0) { mCallback = callback; Loading @@ -420,19 +425,27 @@ Return<Result> StreamOut::clearCallback() { // static int StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie) { wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie)); sp<StreamOut> self = weakSelf.promote(); if (self == nullptr || self->mCallback == nullptr) return 0; // It is guaranteed that the callback thread is joined prior // to exiting from StreamOut's destructor. Must *not* use sp<StreamOut> // here because it can make this code the last owner of StreamOut, // and an attempt to run the destructor on the callback thread // will cause a deadlock in the legacy HAL code. StreamOut *self = reinterpret_cast<StreamOut*>(cookie); // It's correct to hold an sp<> to callback because the reference // in the StreamOut instance can be cleared in the meantime. There is // no difference on which thread to run IStreamOutCallback's destructor. sp<IStreamOutCallback> callback = self->mCallback; if (callback.get() == nullptr) return 0; ALOGV("asyncCallback() event %d", event); switch (event) { case STREAM_CBK_EVENT_WRITE_READY: self->mCallback->onWriteReady(); callback->onWriteReady(); break; case STREAM_CBK_EVENT_DRAIN_READY: self->mCallback->onDrainReady(); callback->onDrainReady(); break; case STREAM_CBK_EVENT_ERROR: self->mCallback->onError(); callback->onError(); break; default: ALOGW("asyncCallback() unknown event %d", event); Loading broadcastradio/2.0/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -21,9 +21,11 @@ hidl_interface { "IdentifierType", "Metadata", "MetadataKey", "ProgramFilter", "ProgramIdentifier", "ProgramInfo", "ProgramInfoFlags", "ProgramListChunk", "ProgramSelector", "Properties", "Result", Loading broadcastradio/2.0/ITunerCallback.hal +15 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,21 @@ interface ITunerCallback { */ oneway onCurrentProgramInfoChanged(ProgramInfo info); /** * A delta update of the program list, called whenever there's a change in * the list. * * If there are frequent changes, HAL implementation must throttle the rate * of the updates. * * There is a hard limit on binder transaction buffer, and the list must * not exceed it. For large lists, HAL implementation must split them to * multiple chunks, no larger than 500kiB each. * * @param chunk A chunk of the program list update. */ oneway onProgramListUpdated(ProgramListChunk chunk); /** * Method called by the HAL when the antenna gets connected or disconnected. * Loading broadcastradio/2.0/ITunerSession.hal +26 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,32 @@ interface ITunerSession { */ cancel(); /** * Applies a filter to the program list and starts sending program list * updates over onProgramListUpdated callback. * * There may be only one updates stream active at the moment. Calling this * method again must result in cancelling the previous update request. * * This call clears the program list on the client side, the HAL must send * the whole list again. * * If the program list scanning hardware (i.e. background tuner) is * unavailable at the moment, the call must succeed and start updates * when it becomes available. * * @param filter Filter to apply on the fetched program list. * @return result OK successfully started fetching list updates. * NOT_SUPPORTED program list scanning is not supported * by the hardware. */ startProgramListUpdates(ProgramFilter filter) generates (Result result); /** * Stops sending program list updates. */ stopProgramListUpdates(); /** * Fetches the current setting of a given config flag. * Loading broadcastradio/2.0/default/TunerSession.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ namespace delay { static constexpr auto scan = 200ms; static constexpr auto step = 100ms; static constexpr auto tune = 150ms; static constexpr auto list = 1s; } // namespace delay Loading Loading @@ -205,6 +206,38 @@ Return<void> TunerSession::cancel() { return {}; } Return<Result> TunerSession::startProgramListUpdates(const ProgramFilter& filter) { ALOGV("%s(%s)", __func__, toString(filter).c_str()); lock_guard<mutex> lk(mMut); if (mIsClosed) return Result::INVALID_STATE; auto list = virtualRadio().getProgramList(); vector<VirtualProgram> filteredList; auto filterCb = [&filter](const VirtualProgram& program) { return utils::satisfies(filter, program.selector); }; std::copy_if(list.begin(), list.end(), std::back_inserter(filteredList), filterCb); auto task = [this, list]() { lock_guard<mutex> lk(mMut); ProgramListChunk chunk = {}; chunk.purge = true; chunk.complete = true; chunk.modified = hidl_vec<ProgramInfo>(list.begin(), list.end()); mCallback->onProgramListUpdated(chunk); }; mThread.schedule(task, delay::list); return Result::OK; } Return<void> TunerSession::stopProgramListUpdates() { ALOGV("%s", __func__); return {}; } Return<void> TunerSession::getConfigFlag(ConfigFlag flag, getConfigFlag_cb _hidl_cb) { ALOGV("%s(%s)", __func__, toString(flag).c_str()); Loading Loading
audio/2.0/default/StreamOut.cpp +19 −6 Original line number Diff line number Diff line Loading @@ -164,6 +164,9 @@ StreamOut::~StreamOut() { } mCallback.clear(); mDevice->closeOutputStream(mStream); // Closing the output stream in the HAL waits for the callback to finish, // and joins the callback thread. Thus is it guaranteed that the callback // thread will not be accessing our object anymore. mStream = nullptr; } Loading Loading @@ -404,6 +407,8 @@ Return<void> StreamOut::getNextWriteTimestamp( Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) { if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED; // Safe to pass 'this' because it is guaranteed that the callback thread // is joined prior to exit from StreamOut's destructor. int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this); if (result == 0) { mCallback = callback; Loading @@ -420,19 +425,27 @@ Return<Result> StreamOut::clearCallback() { // static int StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie) { wp<StreamOut> weakSelf(reinterpret_cast<StreamOut*>(cookie)); sp<StreamOut> self = weakSelf.promote(); if (self == nullptr || self->mCallback == nullptr) return 0; // It is guaranteed that the callback thread is joined prior // to exiting from StreamOut's destructor. Must *not* use sp<StreamOut> // here because it can make this code the last owner of StreamOut, // and an attempt to run the destructor on the callback thread // will cause a deadlock in the legacy HAL code. StreamOut *self = reinterpret_cast<StreamOut*>(cookie); // It's correct to hold an sp<> to callback because the reference // in the StreamOut instance can be cleared in the meantime. There is // no difference on which thread to run IStreamOutCallback's destructor. sp<IStreamOutCallback> callback = self->mCallback; if (callback.get() == nullptr) return 0; ALOGV("asyncCallback() event %d", event); switch (event) { case STREAM_CBK_EVENT_WRITE_READY: self->mCallback->onWriteReady(); callback->onWriteReady(); break; case STREAM_CBK_EVENT_DRAIN_READY: self->mCallback->onDrainReady(); callback->onDrainReady(); break; case STREAM_CBK_EVENT_ERROR: self->mCallback->onError(); callback->onError(); break; default: ALOGW("asyncCallback() unknown event %d", event); Loading
broadcastradio/2.0/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -21,9 +21,11 @@ hidl_interface { "IdentifierType", "Metadata", "MetadataKey", "ProgramFilter", "ProgramIdentifier", "ProgramInfo", "ProgramInfoFlags", "ProgramListChunk", "ProgramSelector", "Properties", "Result", Loading
broadcastradio/2.0/ITunerCallback.hal +15 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,21 @@ interface ITunerCallback { */ oneway onCurrentProgramInfoChanged(ProgramInfo info); /** * A delta update of the program list, called whenever there's a change in * the list. * * If there are frequent changes, HAL implementation must throttle the rate * of the updates. * * There is a hard limit on binder transaction buffer, and the list must * not exceed it. For large lists, HAL implementation must split them to * multiple chunks, no larger than 500kiB each. * * @param chunk A chunk of the program list update. */ oneway onProgramListUpdated(ProgramListChunk chunk); /** * Method called by the HAL when the antenna gets connected or disconnected. * Loading
broadcastradio/2.0/ITunerSession.hal +26 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,32 @@ interface ITunerSession { */ cancel(); /** * Applies a filter to the program list and starts sending program list * updates over onProgramListUpdated callback. * * There may be only one updates stream active at the moment. Calling this * method again must result in cancelling the previous update request. * * This call clears the program list on the client side, the HAL must send * the whole list again. * * If the program list scanning hardware (i.e. background tuner) is * unavailable at the moment, the call must succeed and start updates * when it becomes available. * * @param filter Filter to apply on the fetched program list. * @return result OK successfully started fetching list updates. * NOT_SUPPORTED program list scanning is not supported * by the hardware. */ startProgramListUpdates(ProgramFilter filter) generates (Result result); /** * Stops sending program list updates. */ stopProgramListUpdates(); /** * Fetches the current setting of a given config flag. * Loading
broadcastradio/2.0/default/TunerSession.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -45,6 +45,7 @@ namespace delay { static constexpr auto scan = 200ms; static constexpr auto step = 100ms; static constexpr auto tune = 150ms; static constexpr auto list = 1s; } // namespace delay Loading Loading @@ -205,6 +206,38 @@ Return<void> TunerSession::cancel() { return {}; } Return<Result> TunerSession::startProgramListUpdates(const ProgramFilter& filter) { ALOGV("%s(%s)", __func__, toString(filter).c_str()); lock_guard<mutex> lk(mMut); if (mIsClosed) return Result::INVALID_STATE; auto list = virtualRadio().getProgramList(); vector<VirtualProgram> filteredList; auto filterCb = [&filter](const VirtualProgram& program) { return utils::satisfies(filter, program.selector); }; std::copy_if(list.begin(), list.end(), std::back_inserter(filteredList), filterCb); auto task = [this, list]() { lock_guard<mutex> lk(mMut); ProgramListChunk chunk = {}; chunk.purge = true; chunk.complete = true; chunk.modified = hidl_vec<ProgramInfo>(list.begin(), list.end()); mCallback->onProgramListUpdated(chunk); }; mThread.schedule(task, delay::list); return Result::OK; } Return<void> TunerSession::stopProgramListUpdates() { ALOGV("%s", __func__); return {}; } Return<void> TunerSession::getConfigFlag(ConfigFlag flag, getConfigFlag_cb _hidl_cb) { ALOGV("%s(%s)", __func__, toString(flag).c_str()); Loading