/* * Copyright (c) 2025 Huawei Device Co., Ltd. * 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 #include #include "migrate_avsession_proxy.h" #include "avsession_log.h" #include "avsession_utils.h" #include "avsession_service.h" #include "softbus/softbus_session_utils.h" #include "int_wrapper.h" #include "string_wrapper.h" #include "bool_wrapper.h" namespace OHOS::AVSession { MigrateAVSessionProxy::MigrateAVSessionProxy(AVSessionService *ptr, int32_t mode, std::string deviceId) { std::lock_guard lockGuard(migrateProxyDeviceIdLock_); SLOGI("migrateproxy construct with mode:%{public}d,localDevId:%{public}s.", mode, SoftbusSessionUtils::AnonymizeDeviceId(deviceId).c_str()); mMode_ = mode; servicePtr_ = ptr; localDeviceId_ = deviceId; } MigrateAVSessionProxy::~MigrateAVSessionProxy() { if (checkConnectWorker_.joinable()) { checkConnectWorker_.join(); } SLOGI("MigrateAVSessionProxy destruct with disconnect process."); OnDisconnectServer(deviceId_); } void MigrateAVSessionProxy::SetUserId(int32_t userId) { userId_ = userId; } void MigrateAVSessionProxy::OnConnectServer(const std::string &deviceId) { SLOGI("MigrateAVSessionProxy OnConnectServer:%{public}s.", SoftbusSessionUtils::AnonymizeDeviceId(deviceId).c_str()); { std::lock_guard lockGuard(migrateProxyDeviceIdLock_); deviceId_ = deviceId; } if (mMode_ == MSG_HEAD_MODE) { OnConnectForSuper(); } else { OnConnectForNext(); } } void MigrateAVSessionProxy::OnConnectForNext() { SendSpecialKeepAliveData(); PrepareSessionFromRemote(); CHECK_AND_RETURN_LOG(servicePtr_ != nullptr, "OnConnectServer find service ptr null!"); sptr controller; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); controller = preSetController_; } CHECK_AND_RETURN_LOG(controller != nullptr, "OnConnectServer find preSetController null!"); std::vector> sessionControllers; sessionControllers.push_back(controller); servicePtr_->NotifyRemoteDistributedSessionControllersChanged(sessionControllers); } void MigrateAVSessionProxy::OnDisconnectServer(const std::string &deviceId) { { std::lock_guard lockGuard(migrateProxyDeviceIdLock_); SLOGI("MigrateAVSessionProxy OnDisconnectServer:%{public}s.", SoftbusSessionUtils::AnonymizeDeviceId(deviceId).c_str()); if (deviceId != deviceId_) { SLOGE("proxy onDisconnect but not:%{public}s.", SoftbusSessionUtils::AnonymizeDeviceId(deviceId_).c_str()); return; } deviceId_ = ""; } if (mMode_ == MSG_HEAD_MODE) { OnDisconnectForSuper(); } else { OnDisconnectForNext(); } } void MigrateAVSessionProxy::OnDisconnectForNext() { { std::lock_guard lock(keepAliveMtx_); keepAliveCv_.notify_all(); } if (keepAliveWorker_.joinable()) { keepAliveWorker_.join(); } std::vector> sessionControllers; CHECK_AND_RETURN_LOG(servicePtr_ != nullptr, "OnDisconnectServer find service ptr null!"); servicePtr_->NotifyRemoteDistributedSessionControllersChanged(sessionControllers); ReleaseSessionFromRemote(); servicePtr_->NotifyRemoteBundleChange(""); elementName_.SetAbilityName(""); elementName_.SetBundleName(""); SLOGI("MigrateAVSessionProxy OnDisconnectServer complete"); } int32_t MigrateAVSessionProxy::GetCharacteristic() { return mMode_; } //LCOV_EXCL_START void MigrateAVSessionProxy::OnBytesReceived(const std::string &deviceId, const std::string &data) { if (mMode_ == MSG_HEAD_MODE) { OnBytesRecvForSuper(deviceId, data); } else { OnBytesRecvForNext(deviceId, data); } } void MigrateAVSessionProxy::OnBytesRecvForNext(const std::string &deviceId, const std::string &data) { CHECK_AND_RETURN_LOG(data.length() > MSG_HEAD_LENGTH, "OnBytesReceived too short to process"); int32_t infoType = data[1]; SLOGI("OnBytesReceived with infoType: %{public}d", infoType); std::string jsonStr = data.substr(MSG_HEAD_LENGTH); if (infoType == SYNC_FOCUS_MEDIA_IMAGE) { ProcessMediaImage(jsonStr); return; } else if (infoType == SYNC_FOCUS_BUNDLE_IMG) { ProcessBundleImg(jsonStr); return; } cJSON* jsonValue = nullptr; CHECK_AND_RETURN_LOG(SoftbusSessionUtils::TransferStrToJson(jsonStr, jsonValue), "OnBytes err parse json"); switch (infoType) { case SYNC_PROTOCOL_VERSION: ProcessProtocolVersion(jsonValue, deviceId); break; case SYNC_FOCUS_SESSION_INFO: ProcessSessionInfo(jsonValue); break; case SYNC_FOCUS_META_INFO: ProcessMetaData(jsonValue); break; case SYNC_FOCUS_PLAY_STATE: ProcessPlaybackState(jsonValue); break; case SYNC_FOCUS_VALID_COMMANDS: ProcessValidCommands(jsonValue); break; case SYNC_SET_VOLUME_COMMAND: ProcessVolumeControlCommand(jsonValue); break; case SYNC_AVAIL_DEVICES_LIST: ProcessAvailableDevices(jsonValue); break; case SYNC_CURRENT_DEVICE: ProcessPreferredOutputDevice(jsonValue); break; case SYNC_LONG_PAUSE_NOTIFY: ProcessLongPauseNotify(jsonValue); break; default: SLOGE("OnBytesReceived with unknow infoType:%{public}d", infoType); break; } if (jsonValue != nullptr) { cJSON_Delete(jsonValue); } } //LCOV_EXCL_STOP void MigrateAVSessionProxy::HandlePlay() { SendControlCommandMsg(AVControlCommand::SESSION_CMD_PLAY, DEFAULT_STRING); } void MigrateAVSessionProxy::HandlePause() { SendControlCommandMsg(AVControlCommand::SESSION_CMD_PAUSE, DEFAULT_STRING); } void MigrateAVSessionProxy::HandlePlayNext() { SendControlCommandMsg(AVControlCommand::SESSION_CMD_PLAY_NEXT, DEFAULT_STRING); } void MigrateAVSessionProxy::HandlePlayPrevious() { SendControlCommandMsg(AVControlCommand::SESSION_CMD_PLAY_PREVIOUS, DEFAULT_STRING); } void MigrateAVSessionProxy::HandleToggleFavorite(const std::string& mediaId) { SendControlCommandMsg(AVControlCommand::SESSION_CMD_TOGGLE_FAVORITE, mediaId); } void MigrateAVSessionProxy::HandleCommonCommand(const std::string& commonCommand, const AAFwk::WantParams& commandArgs) { SLOGI("HandleCommonCommand with command:%{public}s", commonCommand.c_str()); } void MigrateAVSessionProxy::GetDistributedSessionControllerList(std::vector>& controllerList) { if (mMode_ == MSG_HEAD_MODE) { GetControllerListForSuper(controllerList); } else { GetControllerListForNext(controllerList); } } void MigrateAVSessionProxy::GetControllerListForNext(std::vector>& controllerList) { sptr controller; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); controller = preSetController_; } CHECK_AND_RETURN_LOG(controller != nullptr, "GetDistributedSessionControllerList with controller null"); controllerList.insert(controllerList.begin(), controller); } void MigrateAVSessionProxy::PrepareSessionFromRemote() { SLOGI("PrepareSessionFromRemote in"); AVSessionDescriptor descriptor; descriptor.sessionId_ = DEFAULT_STRING; descriptor.sessionTag_ = DEFAULT_STRING; descriptor.sessionType_ = AVSession::SESSION_TYPE_AUDIO; descriptor.elementName_.SetBundleName(DEFAULT_STRING); descriptor.elementName_.SetAbilityName(DEFAULT_STRING); descriptor.isThirdPartyApp_ = false; sptr sessionItem = new(std::nothrow) AVSessionItem(descriptor); CHECK_AND_RETURN_LOG(sessionItem != nullptr, "create avsession but get nullptr"); sessionItem->SetPid(DEFAULT_NUM); sessionItem->SetUid(DEFAULT_NUM); OutputDeviceInfo outputDeviceInfo; DeviceInfo deviceInfo; deviceInfo.castCategory_ = AVCastCategory::CATEGORY_REMOTE; deviceInfo.deviceId_ = DEFAULT_STRING; deviceInfo.deviceName_ = DEFAULT_STRING; outputDeviceInfo.deviceInfos_.emplace_back(deviceInfo); sessionItem->SetOutputDevice(outputDeviceInfo); std::weak_ptr migrateProxyWeak(shared_from_this()); std::shared_ptr callback = std::make_shared(sessionItem->GetSessionId(), migrateProxyWeak); sessionItem->RegisterAVSessionCallback(callback); PrepareControllerOfRemoteSession(sessionItem); { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); remoteSession_ = sessionItem; } SLOGI("PrepareSessionFromRemote done"); } void MigrateAVSessionProxy::PrepareControllerOfRemoteSession(sptr sessionItem) { CHECK_AND_RETURN_LOG(sessionItem != nullptr, "PrepareControllerOfRemoteSession with remote session null"); sptr controller = new(std::nothrow) AVControllerItem(DEFAULT_NUM, sessionItem); CHECK_AND_RETURN_LOG(controller != nullptr, "PrepareControllerOfRemoteSession with controller create null"); migrateProxyCallback_ = MigrateAVSessionProxyControllerCallback(); controller->RegisterMigrateAVSessionProxyCallback(migrateProxyCallback_); sessionItem->AddController(DEFAULT_NUM, controller); { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); preSetController_ = controller; } } void MigrateAVSessionProxy::ReleaseSessionFromRemote() { SLOGI("ReleaseSessionFromRemote in"); ReleaseControllerOfRemoteSession(); sptr sessionItem = nullptr; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); sessionItem = remoteSession_; remoteSession_ = nullptr; } CHECK_AND_RETURN_LOG(sessionItem != nullptr, "ReleaseSessionFromRemote with remoteSession null"); sessionItem->RegisterAVSessionCallback(nullptr); sessionItem->DestroyTask(); SLOGI("ReleaseSessionFromRemote done."); } void MigrateAVSessionProxy::ReleaseControllerOfRemoteSession() { sptr controller; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); controller = preSetController_; preSetController_ = nullptr; } CHECK_AND_RETURN_LOG(controller != nullptr, "ReleaseControllerOfRemoteSession with preSetController null"); controller->RegisterMigrateAVSessionProxyCallback(nullptr); controller->DestroyWithoutReply(); SLOGI("ReleaseControllerOfRemoteSession done."); } const MigrateAVSessionProxyControllerCallbackFunc MigrateAVSessionProxy::MigrateAVSessionProxyControllerCallback() { return [this](const std::string& extraEvent, AAFwk::WantParams& extras) { const auto& it = AUDIO_EVENT_MAPS.find(extraEvent); if (it == AUDIO_EVENT_MAPS.end()) { SLOGE("extraEvent %{public}s not support", extraEvent.c_str()); return ERR_COMMAND_NOT_SUPPORT; } switch (it->second) { case AUDIO_NUM_SET_VOLUME: SetVolume(extras); break; case AUDIO_NUM_SELECT_OUTPUT_DEVICE: SelectOutputDevice(extras); break; case AUDIO_NUM_GET_VOLUME: GetVolume(extras); break; case AUDIO_NUM_GET_AVAILABLE_DEVICES: GetAvailableDevices(extras); break; case AUDIO_NUM_GET_PREFERRED_OUTPUT_DEVICE_FOR_RENDERER_INFO: GetPreferredOutputDeviceForRendererInfo(extras); break; case SESSION_NUM_COLD_START_FROM_PROXY: if (mMode_ == MSG_HEAD_MODE) { ColdStartForSuper(extras); } else { ColdStartFromProxy(); } break; case SESSION_NUM_SET_MEDIACONTROL_NEED_STATE: NotifyMediaControlNeedStateChange(extras); break; case SESSION_NUM_SET_MEDIACONTROL_SYNC_TIME: NotifyMediaControlSyncTime(extras); break; case AUDIO_NUM_GET_VERSION: GetVersion(extras); break; default: break; } return AVSESSION_SUCCESS; }; } void MigrateAVSessionProxy::SetVolume(const AAFwk::WantParams& extras) { SLOGI("proxy send in SetVolume case"); CHECK_AND_RETURN_LOG(extras.HasParam(AUDIO_SET_VOLUME), "extras not have event"); auto volume = extras.GetParam(AUDIO_SET_VOLUME); AAFwk::IInteger* ao = AAFwk::IInteger::Query(volume); CHECK_AND_RETURN_LOG(ao != nullptr, "extras have no value"); volumeNum_.store(OHOS::AAFwk::Integer::Unbox(ao)); cJSON* value = SoftbusSessionUtils::GetNewCJSONObject(); if (value == nullptr) { SLOGE("get json value fail"); return; } if (!SoftbusSessionUtils::AddIntToJson(value, AUDIO_VOLUME, volumeNum_.load())) { SLOGE("AddIntToJson with key:%{public}s|value:%{public}d fail", AUDIO_VOLUME, volumeNum_.load()); cJSON_Delete(value); return; } std::string msg = std::string({mMode_, SYNC_SET_VOLUME_COMMAND}); SoftbusSessionUtils::TransferJsonToStr(value, msg); cJSON_Delete(value); SendByteForNext(deviceId_, msg); } void MigrateAVSessionProxy::SelectOutputDevice(const AAFwk::WantParams& extras) { SLOGI("proxy send in SelectOutputDevice case"); CHECK_AND_RETURN_LOG(extras.HasParam(AUDIO_SELECT_OUTPUT_DEVICE), "extras not have event"); auto value = extras.GetParam(AUDIO_SELECT_OUTPUT_DEVICE); AAFwk::IString* stringValue = AAFwk::IString::Query(value); CHECK_AND_RETURN_LOG(stringValue != nullptr, "extras have no value"); std::string deviceValue = AAFwk::String::Unbox(stringValue); std::string msg = std::string({mMode_, SYNC_SWITCH_AUDIO_DEVICE_COMMAND}); SendJsonStringByte(deviceId_, msg + deviceValue); } void MigrateAVSessionProxy::GetVolume(AAFwk::WantParams& extras) { SLOGI("proxy send in GetVolume case"); extras.SetParam(AUDIO_GET_VOLUME, OHOS::AAFwk::Integer::Box(volumeNum_.load())); } void MigrateAVSessionProxy::GetAvailableDevices(AAFwk::WantParams& extras) { SLOGI("proxy send in GetAvailableDevices case"); cJSON* jsonData; { std::lock_guard lock(devicesLock_); jsonData = MigrateAVSessionServer::ConvertAudioDeviceDescriptorsToJson(availableDevices_); } CHECK_AND_RETURN_LOG(jsonData != nullptr, "get jsonData nullptr"); if (cJSON_IsInvalid(jsonData) || cJSON_IsNull(jsonData)) { SLOGE("get jsonData invalid"); cJSON_Delete(jsonData); return; } cJSON* jsonArray = cJSON_GetObjectItem(jsonData, MEDIA_AVAILABLE_DEVICES_LIST); if (jsonArray == nullptr || cJSON_IsInvalid(jsonArray) || cJSON_IsNull(jsonArray)) { SLOGE("get jsonArray invalid"); cJSON_Delete(jsonData); return; } std::string jsonStr; SoftbusSessionUtils::TransferJsonToStr(jsonArray, jsonStr); if (jsonStr.empty()) { SLOGE("get jsonStr empty"); cJSON_Delete(jsonData); return; } extras.SetParam(AUDIO_GET_AVAILABLE_DEVICES, OHOS::AAFwk::String::Box(jsonStr)); cJSON_Delete(jsonData); } void MigrateAVSessionProxy::GetPreferredOutputDeviceForRendererInfo(AAFwk::WantParams& extras) { SLOGI("proxy send in GetPreferredOutputDeviceForRendererInfo case"); cJSON* jsonData; { std::lock_guard lock(devicesLock_); jsonData = MigrateAVSessionServer::ConvertAudioDeviceDescriptorsToJson(preferredOutputDevice_); } CHECK_AND_RETURN_LOG(jsonData != nullptr, "get jsonData nullptr"); if (cJSON_IsInvalid(jsonData) || cJSON_IsNull(jsonData)) { SLOGE("get jsonData invalid"); cJSON_Delete(jsonData); return; } cJSON* jsonArray = cJSON_GetObjectItem(jsonData, MEDIA_AVAILABLE_DEVICES_LIST); if (jsonArray == nullptr || cJSON_IsInvalid(jsonArray) || cJSON_IsNull(jsonArray)) { SLOGE("get jsonArray invalid"); cJSON_Delete(jsonData); return; } std::string jsonStr; SoftbusSessionUtils::TransferJsonToStr(jsonArray, jsonStr); if (jsonStr.empty()) { SLOGE("get jsonStr empty"); cJSON_Delete(jsonData); return; } extras.SetParam(AUDIO_GET_PREFERRED_OUTPUT_DEVICE_FOR_RENDERER_INFO, OHOS::AAFwk::String::Box(jsonStr)); cJSON_Delete(jsonData); } void MigrateAVSessionProxy::GetVersion(AAFwk::WantParams& extras) { std::lock_guard lock(versionMapMtx_); auto it = deviceVersionMap_.find(deviceId_); if (it != deviceVersionMap_.end()) { SLOGI("GetVersion for device:%{public}s version:%{public}d", deviceId_.c_str(), it->second); extras.SetParam(AUDIO_GET_VERSION, OHOS::AAFwk::Integer::Box(it->second)); } else { SLOGI("GetVersion no version for device:%{public}s", deviceId_.c_str()); extras.SetParam(AUDIO_GET_VERSION, OHOS::AAFwk::Integer::Box(AVSESSION_DEFAULT_VERSION)); } } void MigrateAVSessionProxy::ColdStartFromProxy() { SLOGI("proxy send in ColdStartFromProxy case with bundleName:%{public}s", elementName_.GetAbilityName().c_str()); std::string msg = std::string({mMode_, COLD_START}); cJSON* controlMsg = SoftbusSessionUtils::GetNewCJSONObject(); if (controlMsg == nullptr) { SLOGE("get controlMsg fail"); return; } if (!SoftbusSessionUtils::AddStringToJson(controlMsg, MIGRATE_BUNDLE_NAME, elementName_.GetAbilityName())) { SLOGE("AddStringToJson with key:%{public}s|value:%{public}s fail", MIGRATE_BUNDLE_NAME, elementName_.GetAbilityName().c_str()); cJSON_Delete(controlMsg); return; } SoftbusSessionUtils::TransferJsonToStr(controlMsg, msg); SendByteForNext(deviceId_, msg); cJSON_Delete(controlMsg); } void MigrateAVSessionProxy::ProcessSessionInfo(cJSON* jsonValue) { sptr sessionItem = nullptr; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); sessionItem = remoteSession_; } CHECK_AND_RETURN_LOG(sessionItem != nullptr, "ProcessSessionInfo with remote session null"); if (jsonValue == nullptr || cJSON_IsInvalid(jsonValue) || cJSON_IsNull(jsonValue)) { SLOGE("get jsonValue invalid"); return; } std::string bundleNameBef = elementName_.GetBundleName(); std::string bundleName = SoftbusSessionUtils::GetStringFromJson(jsonValue, MIGRATE_BUNDLE_NAME); bundleName = bundleName.empty() ? DEFAULT_STRING : bundleName; elementName_.SetBundleName(bundleName); std::string abilityName = SoftbusSessionUtils::GetStringFromJson(jsonValue, MIGRATE_ABILITY_NAME); abilityName = abilityName.empty() ? DEFAULT_STRING : abilityName; elementName_.SetAbilityName(abilityName); std::string sessionId = SoftbusSessionUtils::GetStringFromJson(jsonValue, MIGRATE_SESSION_ID); sessionId = sessionId.empty() ? DEFAULT_STRING : sessionId; if (sessionId.empty() || sessionId == DEFAULT_STRING || sessionId == EMPTY_SESSION) { sessionItem->Deactivate(); elementName_.SetAbilityName(elementName_.GetBundleName()); elementName_.SetBundleName(""); } else { sessionItem->Activate(); } SLOGI("ProcessSessionInfo with sessionId:%{public}s|bundleName:%{public}s done.", SoftbusSessionUtils::AnonymizeDeviceId(sessionId).c_str(), bundleName.c_str()); servicePtr_->NotifyRemoteBundleChange(elementName_.GetBundleName()); if (bundleNameBef != elementName_.GetBundleName()) { AVPlaybackState playbackState; playbackState.SetState(0); playbackState.SetFavorite(false); sessionItem->SetAVPlaybackState(playbackState); AVMetaData metaData; metaData.SetAssetId(DEFAULT_STRING); metaData.SetWriter(bundleName); metaData.SetTitle(""); metaData.SetArtist(""); metaData.SetPreviousAssetId(""); sessionItem->SetAVMetaData(metaData); } SendMediaControlNeedStateMsg(); } bool MigrateAVSessionProxy::CheckMediaAlive() { return !elementName_.GetBundleName().empty(); } void MigrateAVSessionProxy::ProcessMetaData(cJSON* jsonValue) { sptr sessionItem = nullptr; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); sessionItem = remoteSession_; } CHECK_AND_RETURN_LOG(sessionItem != nullptr, "ProcessMetaData with remote session null"); if (jsonValue == nullptr || cJSON_IsInvalid(jsonValue) || cJSON_IsNull(jsonValue)) { SLOGE("get jsonValue invalid"); return; } AVMetaData metaData; if (AVSESSION_SUCCESS != sessionItem->GetAVMetaData(metaData)) { SLOGE("ProcessMetaData GetAVMetaData fail"); } if (cJSON_HasObjectItem(jsonValue, METADATA_ASSET_ID)) { std::string assetId = SoftbusSessionUtils::GetStringFromJson(jsonValue, METADATA_ASSET_ID); if (assetId.empty()) { assetId = DEFAULT_STRING; } std::string oldAsset = metaData.GetAssetId(); if (oldAsset != assetId) { metaData.SetTitle(""); metaData.SetArtist(""); } metaData.SetAssetId(assetId); } if (cJSON_HasObjectItem(jsonValue, METADATA_TITLE)) { std::string title = SoftbusSessionUtils::GetStringFromJson(jsonValue, METADATA_TITLE); if (title.empty()) { title = DEFAULT_STRING; } metaData.SetTitle(title); } if (cJSON_HasObjectItem(jsonValue, METADATA_ARTIST)) { std::string artist = SoftbusSessionUtils::GetStringFromJson(jsonValue, METADATA_ARTIST); if (artist.empty()) { artist = DEFAULT_STRING; } metaData.SetArtist(artist); } sessionItem->SetAVMetaData(metaData); } void MigrateAVSessionProxy::ProcessPlaybackState(cJSON* jsonValue) { sptr sessionItem = nullptr; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); sessionItem = remoteSession_; } CHECK_AND_RETURN_LOG(sessionItem != nullptr, "ProcessPlaybackState with remote session null"); if (jsonValue == nullptr || cJSON_IsInvalid(jsonValue) || cJSON_IsNull(jsonValue)) { SLOGE("get jsonValue invalid"); return; } AVPlaybackState playbackState; if (AVSESSION_SUCCESS != sessionItem->GetAVPlaybackState(playbackState)) { SLOGE("ProcessPlaybackState GetAVPlaybackState fail"); } if (cJSON_HasObjectItem(jsonValue, PLAYBACK_STATE)) { int state = SoftbusSessionUtils::GetIntFromJson(jsonValue, PLAYBACK_STATE); playbackState.SetState(state); } if (cJSON_HasObjectItem(jsonValue, FAVOR_STATE)) { int isFavor = SoftbusSessionUtils::GetBoolFromJson(jsonValue, FAVOR_STATE); playbackState.SetFavorite(isFavor); } sessionItem->SetAVPlaybackState(playbackState); SLOGI("ProcessPlaybackState set state:%{public}d | isFavor:%{public}d", playbackState.GetState(), playbackState.GetFavorite()); } void MigrateAVSessionProxy::ProcessValidCommands(cJSON* jsonValue) { sptr sessionItem = nullptr; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); sessionItem = remoteSession_; } CHECK_AND_RETURN_LOG(sessionItem != nullptr, "ProcessValidCommands with remote session null"); if (jsonValue == nullptr || cJSON_IsInvalid(jsonValue) || cJSON_IsNull(jsonValue)) { SLOGE("get jsonValue invalid"); return; } std::vector commands; if (cJSON_HasObjectItem(jsonValue, VALID_COMMANDS)) { std::string commandsStr = SoftbusSessionUtils::GetStringFromJson(jsonValue, VALID_COMMANDS); if (commandsStr.empty()) { commandsStr = DEFAULT_STRING; } for (unsigned long i = 0; i < commandsStr.length(); i++) { commands.insert(commands.begin(), static_cast(commandsStr[i] - '0')); } sessionItem->SetSupportCommand(commands); } SLOGI("ProcessValidCommands set cmd size:%{public}d", static_cast(commands.size())); } void MigrateAVSessionProxy::ProcessVolumeControlCommand(cJSON* jsonValue) { SLOGI("proxy recv in ProcessVolumeControlCommand case"); if (jsonValue == nullptr || cJSON_IsInvalid(jsonValue) || cJSON_IsNull(jsonValue)) { SLOGE("get jsonValue invalid"); return; } if (!cJSON_HasObjectItem(jsonValue, AUDIO_VOLUME)) { SLOGE("json parse with error member"); return; } int32_t volume = SoftbusSessionUtils::GetIntFromJson(jsonValue, AUDIO_VOLUME); CHECK_AND_RETURN_LOG(volume >= 0, "Invalid volume value: %{public}d", volume); volumeNum_.store(volume); AAFwk::WantParams args; args.SetParam(AUDIO_CALLBACK_VOLUME, OHOS::AAFwk::Integer::Box(volumeNum_.load())); sptr controller; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); controller = preSetController_; } CHECK_AND_RETURN_LOG(controller != nullptr, "preSetController_ is nullptr"); controller->HandleSetSessionEvent(AUDIO_CALLBACK_VOLUME, args); } void DevicesJsonArrayToVector(cJSON* jsonArray, AudioDeviceDescriptors& devices) { if (jsonArray == nullptr || cJSON_IsInvalid(jsonArray) || !cJSON_IsArray(jsonArray)) { SLOGE("get jsonArray invalid"); return; } devices.clear(); cJSON* jsonObject = nullptr; cJSON_ArrayForEach(jsonObject, jsonArray) { CHECK_AND_CONTINUE(jsonObject != nullptr && !cJSON_IsInvalid(jsonObject)); int deviceCategory = SoftbusSessionUtils::GetIntFromJson(jsonObject, AUDIO_DEVICE_CATEGORY); int deviceType = SoftbusSessionUtils::GetIntFromJson(jsonObject, AUDIO_DEVICE_TYPE); int deviceRole = SoftbusSessionUtils::GetIntFromJson(jsonObject, AUDIO_DEVICE_ROLE); std::string networkId = SoftbusSessionUtils::GetStringFromJson(jsonObject, AUDIO_NETWORK_ID); std::string deviceName = SoftbusSessionUtils::GetStringFromJson(jsonObject, AUDIO_DEVICE_NAME); std::string macAddress = SoftbusSessionUtils::GetStringFromJson(jsonObject, AUDIO_MAC_ADDRESS); std::shared_ptr device = std::make_shared(); CHECK_AND_RETURN_LOG(device != nullptr, "AudioDeviceDescriptor make shared_ptr is nullptr"); device->deviceCategory_ = static_cast(deviceCategory); device->deviceType_ = static_cast(deviceType); device->deviceRole_ = static_cast(deviceRole); device->networkId_ = networkId; device->deviceName_ = deviceName; device->macAddress_ = macAddress; devices.push_back(device); } } void MigrateAVSessionProxy::ProcessAvailableDevices(cJSON* jsonValue) { SLOGI("proxy recv in ProcessAvailableDevices case"); if (jsonValue == nullptr || cJSON_IsInvalid(jsonValue) || cJSON_IsNull(jsonValue)) { SLOGE("get jsonValue invalid"); return; } CHECK_AND_RETURN_LOG(cJSON_HasObjectItem(jsonValue, MEDIA_AVAILABLE_DEVICES_LIST), "json parse with error member"); cJSON* jsonArray = cJSON_GetObjectItem(jsonValue, MEDIA_AVAILABLE_DEVICES_LIST); CHECK_AND_RETURN_LOG(jsonArray != nullptr && !cJSON_IsInvalid(jsonArray) && cJSON_IsArray(jsonArray), "json object is not array"); { std::lock_guard lock(devicesLock_); DevicesJsonArrayToVector(jsonArray, availableDevices_); } std::string jsonStr; SoftbusSessionUtils::TransferJsonToStr(jsonArray, jsonStr); AAFwk::WantParams args; args.SetParam(AUDIO_CALLBACK_AVAILABLE_DEVICES, OHOS::AAFwk::String::Box(jsonStr)); sptr controller; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); controller = preSetController_; } CHECK_AND_RETURN_LOG(controller != nullptr, "preSetController_ is nullptr"); controller->HandleSetSessionEvent(AUDIO_CALLBACK_AVAILABLE_DEVICES, args); } void MigrateAVSessionProxy::ProcessPreferredOutputDevice(cJSON* jsonValue) { SLOGI("proxy recv in ProcessPreferredOutputDevice case"); if (jsonValue == nullptr || cJSON_IsInvalid(jsonValue) || cJSON_IsNull(jsonValue)) { SLOGE("get jsonValue invalid"); return; } CHECK_AND_RETURN_LOG(cJSON_HasObjectItem(jsonValue, MEDIA_AVAILABLE_DEVICES_LIST), "json parse with error member"); cJSON* jsonArray = cJSON_GetObjectItem(jsonValue, MEDIA_AVAILABLE_DEVICES_LIST); CHECK_AND_RETURN_LOG(jsonArray != nullptr && !cJSON_IsInvalid(jsonArray) && cJSON_IsArray(jsonArray), "json object is not array"); { std::lock_guard lock(devicesLock_); DevicesJsonArrayToVector(jsonArray, preferredOutputDevice_); } std::string jsonStr; SoftbusSessionUtils::TransferJsonToStr(jsonArray, jsonStr); AAFwk::WantParams args; args.SetParam(AUDIO_CALLBACK_PREFERRED_OUTPUT_DEVICE_FOR_RENDERER_INFO, OHOS::AAFwk::String::Box(jsonStr)); sptr controller; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); controller = preSetController_; } CHECK_AND_RETURN_LOG(controller != nullptr, "preSetController_ is nullptr"); controller->HandleSetSessionEvent(AUDIO_CALLBACK_PREFERRED_OUTPUT_DEVICE_FOR_RENDERER_INFO, args); } void MigrateAVSessionProxy::ProcessBundleImg(std::string bundleIconStr) { sptr sessionItem = nullptr; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); sessionItem = remoteSession_; } CHECK_AND_RETURN_LOG(sessionItem != nullptr, "ProcessBundleImg with remote session null"); AVMetaData metaData; if (AVSESSION_SUCCESS != sessionItem->GetAVMetaData(metaData)) { SLOGE("ProcessBundleImg GetAVMetaData fail"); } if (metaData.GetAssetId().empty()) { metaData.SetAssetId(DEFAULT_STRING); } std::vector imgVec(bundleIconStr.begin(), bundleIconStr.end()); if (imgVec.empty()) { SLOGE("ProcessBundleImg with empty img, return"); return; } std::shared_ptr innerPixelMap = std::make_shared(); innerPixelMap->SetInnerImgBuffer(imgVec); metaData.SetBundleIcon(innerPixelMap); sessionItem->SetAVMetaData(metaData); SLOGI("ProcessBundleImg set img size:%{public}d", static_cast(metaData.GetBundleIcon() == nullptr ? -1 : metaData.GetBundleIcon()->GetInnerImgBuffer().size())); } void MigrateAVSessionProxy::ProcessMediaImage(std::string mediaImageStr) { sptr sessionItem = nullptr; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); sessionItem = remoteSession_; } CHECK_AND_RETURN_LOG(sessionItem != nullptr, "ProcessMediaImage with remote session null"); size_t insertPos = mediaImageStr.find('|'); CHECK_AND_RETURN_LOG(insertPos != std::string::npos && insertPos > 0 && insertPos < mediaImageStr.size(), "mediaImgStr do not contain assetId, return"); std::string assetIdForMediaImg = mediaImageStr.substr(0, insertPos); mediaImageStr.erase(0, insertPos + 1); AVMetaData metaData; if (AVSESSION_SUCCESS != sessionItem->GetAVMetaData(metaData)) { SLOGE("ProcessMediaImage GetAVMetaData fail"); } if (metaData.GetAssetId().empty()) { metaData.SetAssetId(assetIdForMediaImg); } metaData.SetPreviousAssetId(assetIdForMediaImg); std::vector imgVec(mediaImageStr.begin(), mediaImageStr.end()); if (imgVec.empty()) { metaData.SetMediaImageUri(DEFAULT_STRING); metaData.SetMediaImage(nullptr); } else { std::shared_ptr innerPixelMap = std::make_shared(); innerPixelMap->SetInnerImgBuffer(imgVec); metaData.SetMediaImageUri(""); metaData.SetMediaImage(innerPixelMap); } SLOGI("ProcessMediaImage set img size:%{public}d", static_cast(metaData.GetMediaImage() == nullptr ? -1 : metaData.GetMediaImage()->GetInnerImgBuffer().size())); sessionItem->SetAVMetaData(metaData); } void MigrateAVSessionProxy::ProcessProtocolVersion(cJSON* jsonValue, const std::string& deviceId) { SLOGI("Received protocol version from phone"); int32_t newVersion = SoftbusSessionUtils::GetIntFromJson(jsonValue, "protocolVersion"); bool versionChanged = false; { std::lock_guard lock(versionMapMtx_); auto it = deviceVersionMap_.find(deviceId); if (it == deviceVersionMap_.end() || it->second != newVersion) { versionChanged = true; } deviceVersionMap_[deviceId] = newVersion; } sptr controller; { std::lock_guard lockGuard(migrateProxyRemoteSessionLock_); controller = preSetController_; } if (versionChanged && controller != nullptr) { AAFwk::WantParams args; args.SetParam(AUDIO_GET_VERSION, OHOS::AAFwk::Integer::Box(newVersion)); controller->HandleSetSessionEvent(AUDIO_GET_VERSION, args); SLOGI("Protocol version changed, notify controller"); } } void MigrateAVSessionProxy::ProcessLongPauseNotify(cJSON* jsonValue) { CHECK_AND_RETURN_LOG(servicePtr_ != nullptr, "servicePtr_ is nullptr"); bool isLongPause = SoftbusSessionUtils::GetBoolFromJson(jsonValue, LONG_PAUSE_STATE); SLOGI("ProcessLongPauseNotify isLongPause:%{public}d", isLongPause); int32_t event = isLongPause ? REMOTE_MEDIA_LONG_PAUSE : REMOTE_MEDIA_LONG_PAUSE_RESUME; servicePtr_->PublishMediaControlState(event); } void MigrateAVSessionProxy::SendControlCommandMsg(int32_t commandCode, std::string commandArgsStr) { SLOGI("SendControlCommandMsg with code:%{public}d", commandCode); std::string msg = std::string({mMode_, SYNC_COMMAND}); cJSON* controlMsg = SoftbusSessionUtils::GetNewCJSONObject(); if (controlMsg == nullptr) { SLOGE("get controlMsg fail"); return; } if (!SoftbusSessionUtils::AddIntToJson(controlMsg, COMMAND_CODE, commandCode)) { SLOGE("AddIntToJson with key:%{public}s|value:%{public}d fail", COMMAND_CODE, commandCode); cJSON_Delete(controlMsg); return; } if (!SoftbusSessionUtils::AddStringToJson(controlMsg, COMMAND_ARGS, commandArgsStr)) { SLOGE("AddStringToJson with key:%{public}s|value:%{public}s fail", COMMAND_ARGS, commandArgsStr.c_str()); cJSON_Delete(controlMsg); return; } SoftbusSessionUtils::TransferJsonToStr(controlMsg, msg); SendByteForNext(deviceId_, msg); cJSON_Delete(controlMsg); } void MigrateAVSessionProxy::SendMediaControlNeedStateMsg(bool isMock) { SLOGI("SendMediaControlNeedStateMsg with state:%{public}d|mock:%{public}d", isNeedByMediaControl.load(), isMock); std::string msg = std::string({mMode_, SYNC_MEDIA_CONTROL_NEED_STATE}); cJSON* controlMsg = SoftbusSessionUtils::GetNewCJSONObject(); if (controlMsg == nullptr) { SLOGE("get controlMsg fail"); return; } if (!SoftbusSessionUtils::AddBoolToJson(controlMsg, NEED_STATE, isMock ? true : isNeedByMediaControl.load())) { SLOGE("AddBoolToJson with key:%{public}s|value:%{public}d fail", NEED_STATE, isNeedByMediaControl.load()); cJSON_Delete(controlMsg); return; } SoftbusSessionUtils::TransferJsonToStr(controlMsg, msg); SendByteForNext(deviceId_, msg); cJSON_Delete(controlMsg); } void MigrateAVSessionProxy::SendMediaControlSyncTime(int32_t timeoutMs) { SLOGI("SendMediaControlSyncTime with state:%{public}d|timeout:%{public}d", isNeedByMediaControl.load(), timeoutMs); std::string msg = std::string({MSG_HEAD_MODE_FOR_NEXT, SYNC_MEDIA_CONTROL_NEED_STATE}); cJSON* controlMsg = SoftbusSessionUtils::GetNewCJSONObject(); if (controlMsg == nullptr) { SLOGE("get controlMsg fail"); return; } if (!SoftbusSessionUtils::AddIntToJson(controlMsg, AVSESSION_PROXY_CURRENT_VERSION, AVSESSION_PROXY_VERSION)) { SLOGE("AddIntToJson with key:%{public}s|value:%{public}d fail", AVSESSION_PROXY_CURRENT_VERSION, AVSESSION_PROXY_VERSION); cJSON_Delete(controlMsg); return; } if (!SoftbusSessionUtils::AddIntToJson(controlMsg, MEDIACONTROL_NEED_STATE_TIMEOUT_MS, timeoutMs)) { SLOGE("AddIntToJson with key:%{public}s|value:%{public}d fail", MEDIACONTROL_NEED_STATE_TIMEOUT_MS, timeoutMs); cJSON_Delete(controlMsg); return; } SoftbusSessionUtils::TransferJsonToStr(controlMsg, msg); SendByteForNext(deviceId_, msg); cJSON_Delete(controlMsg); } void MigrateAVSessionProxy::SendSpecialKeepAliveData() { checkConnectWorker_ = std::thread([this]() { SendMediaControlNeedStateMsg(true); std::this_thread::sleep_for(std::chrono::milliseconds(CHECK_CONNECT_TIME_FOR_NEXT)); SendMediaControlNeedStateMsg(); if (volumeNum_.load() == DEFAULT_FAKE_VOLUME) { SLOGE("no bytes recv aft connect, disconnect process"); std::string deviceIdSnapshot; { std::lock_guard lockGuard(migrateProxyDeviceIdLock_); deviceIdSnapshot = this->deviceId_; } OnDisconnectServer(deviceIdSnapshot); } else { SLOGI("volume recv aft connect:%{public}d", volumeNum_.load()); } }); keepAliveWorker_ = std::thread([this]() { bool isDeviceIdEmpty = false; std::string deviceIdSnapshot; { std::lock_guard lockGuard(migrateProxyDeviceIdLock_); isDeviceIdEmpty = this->deviceId_.empty(); deviceIdSnapshot = this->deviceId_; } while (!isDeviceIdEmpty) { SLOGI("SendSpecialKeepAliveData for deviceId:%{public}s.", SoftbusSessionUtils::AnonymizeDeviceId(deviceIdSnapshot).c_str()); std::string data = std::string({mMode_, SYNC_HEARTBEAT}); SendByteForNext(deviceIdSnapshot, data); std::unique_lock lock(keepAliveMtx_); { std::lock_guard lockGuard(migrateProxyDeviceIdLock_); isDeviceIdEmpty = this->deviceId_.empty(); CHECK_AND_RETURN_LOG(!isDeviceIdEmpty, "SendSpecialKeepAliveData quit for deviceId empty"); } if (!isNeedByMediaControl.load()) { SLOGI("silent bytes waiting."); keepAliveCv_.wait_for(lock, std::chrono::milliseconds(SILENT_HEART_BEAT_TIME_FOR_NEXT)); } else { keepAliveCv_.wait_for(lock, std::chrono::milliseconds(HEART_BEAT_TIME_FOR_NEXT)); } { std::lock_guard lockGuard(migrateProxyDeviceIdLock_); isDeviceIdEmpty = this->deviceId_.empty(); deviceIdSnapshot = this->deviceId_; } } SLOGI("SendSpecialKeepAliveData exit."); }); } void MigrateAVSessionProxy::NotifyMediaControlNeedStateChange(AAFwk::WantParams& extras) { CHECK_AND_RETURN_LOG(extras.HasParam(MEDIACONTROL_NEED_STATE), "extras not have NeedState"); auto value = extras.GetParam(MEDIACONTROL_NEED_STATE); AAFwk::IBoolean* boolValue = AAFwk::IBoolean::Query(value); CHECK_AND_RETURN_LOG(boolValue != nullptr, "extras have no NeedState after query"); bool isNeed = OHOS::AAFwk::Boolean::Unbox(boolValue); SLOGI("refresh NeedState:%{public}d", isNeed); isNeedByMediaControl.store(isNeed); SendMediaControlNeedStateMsg(); } void MigrateAVSessionProxy::NotifyMediaControlSyncTime(AAFwk::WantParams& extras) { CHECK_AND_RETURN_LOG(extras.HasParam(MEDIACONTROL_NEED_STATE), "extras not have NeedState"); auto value = extras.GetParam(MEDIACONTROL_NEED_STATE); AAFwk::IBoolean* boolValue = AAFwk::IBoolean::Query(value); CHECK_AND_RETURN_LOG(boolValue != nullptr, "extras have no NeedState after query"); bool isNeed = OHOS::AAFwk::Boolean::Unbox(boolValue); SLOGI("refresh NeedStateWithTimeout:%{public}d", isNeed); isNeedByMediaControl.store(isNeed); int32_t timeoutMs = NEED_STATE_TIMER_INTERVAL; if (extras.HasParam(MEDIACONTROL_NEED_STATE_TIMEOUT_MS)) { auto timeoutValue = extras.GetParam(MEDIACONTROL_NEED_STATE_TIMEOUT_MS); AAFwk::IInteger* timeoutInt = AAFwk::IInteger::Query(timeoutValue); if (timeoutInt != nullptr) { timeoutMs = OHOS::AAFwk::Integer::Unbox(timeoutInt); SLOGI("Use custom timeout:%{public}d ms", timeoutMs); } } SendMediaControlSyncTime(timeoutMs); } AVSessionObserver::AVSessionObserver(const std::string &playerId, std::weak_ptr migrateProxy) { playerId_ = playerId; migrateProxy_ = migrateProxy; } void AVSessionObserver::OnPlay(const AVControlCommand& cmd) { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); if (proxy->GetCharacteristic() == MSG_HEAD_MODE) { proxy->HandlePlayForSuper(playerId_); } else { proxy->HandlePlay(); } } void AVSessionObserver::OnPause() { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); if (proxy->GetCharacteristic() == MSG_HEAD_MODE) { proxy->HandlePauseForSuper(playerId_); } else { proxy->HandlePause(); } } void AVSessionObserver::OnPlayNext(const AVControlCommand& cmd) { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); if (proxy->GetCharacteristic() == MSG_HEAD_MODE) { proxy->HandlePlayNextForSuper(playerId_); } else { proxy->HandlePlayNext(); } } void AVSessionObserver::OnPlayPrevious(const AVControlCommand& cmd) { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); if (proxy->GetCharacteristic() == MSG_HEAD_MODE) { proxy->HandlePlayPreviousForSuper(playerId_); } else { proxy->HandlePlayPrevious(); } } void AVSessionObserver::OnSeek(int64_t time) { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); if (proxy->GetCharacteristic() == MSG_HEAD_MODE) { proxy->HandleSeekForSuper(playerId_, time); } } void AVSessionObserver::OnToggleFavorite(const std::string& mediaId) { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); if (proxy->GetCharacteristic() == MSG_HEAD_MODE) { proxy->HandleToggleFavoriteForSuper(playerId_, mediaId); } else { proxy->HandleToggleFavorite(mediaId); } } void AVSessionObserver::OnSetLoopMode(int32_t loopMode) { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); if (proxy->GetCharacteristic() == MSG_HEAD_MODE) { proxy->HandleSetLoopModeForSuper(playerId_, loopMode); } } void AVSessionObserver::OnCommonCommand(const std::string& commonCommand, const AAFwk::WantParams& commandArgs) { std::shared_ptr proxy = migrateProxy_.lock(); CHECK_AND_RETURN_LOG(proxy != nullptr, "check migrate proxy nullptr!"); proxy->HandleCommonCommand(commonCommand, commandArgs); } } // namespace OHOS::AVSession