}
}
-string TranslateInterruptedCode(int code) {
- ScopeLogger();
-#define STRINGIFY(c) \
- case c: \
- return #c
- switch (code) {
- STRINGIFY(RADIO_INTERRUPTED_BY_MEDIA);
- STRINGIFY(RADIO_INTERRUPTED_BY_CALL);
- STRINGIFY(RADIO_INTERRUPTED_BY_EARJACK_UNPLUG);
- STRINGIFY(RADIO_INTERRUPTED_BY_RESOURCE_CONFLICT);
- STRINGIFY(RADIO_INTERRUPTED_BY_ALARM);
- STRINGIFY(RADIO_INTERRUPTED_BY_EMERGENCY);
- STRINGIFY(RADIO_INTERRUPTED_BY_RESUMABLE_MEDIA);
- STRINGIFY(RADIO_INTERRUPTED_BY_NOTIFICATION);
+string TranslateInterruptedCode(sound_stream_focus_change_reason_e reason) {
+ ScopeLogger();
+ switch (reason) {
+ case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA:
+ return "RADIO_INTERRUPTED_BY_MEDIA";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_SYSTEM:
+ return "RADIO_INTERRUPTED_BY_SYSTEM";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_ALARM:
+ return "RADIO_INTERRUPTED_BY_ALARM";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_NOTIFICATION:
+ return "RADIO_INTERRUPTED_BY_NOTIFICATION";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_EMERGENCY:
+ return "RADIO_INTERRUPTED_BY_EMERGENCY";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_INFORMATION:
+ return "RADIO_INTERRUPTED_BY_VOICE_INFORMATION";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_VOICE_RECOGNITION:
+ return "RADIO_INTERRUPTED_BY_VOICE_RECOGNITION";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_RINGTONE:
+ return "RADIO_INTERRUPTED_BY_RINGTONE";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_VOIP:
+ return "RADIO_INTERRUPTED_BY_VOIP";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_CALL:
+ return "RADIO_INTERRUPTED_BY_CALL";
+ case SOUND_STREAM_FOCUS_CHANGED_BY_MEDIA_EXTERNAL_ONLY:
+ return "RADIO_INTERRUPTED_BY_MEDIA_EXTERNAL_ONLY";
default:
return "UNKNOWN_INTERRUPTED_ERROR_CODE";
}
-#undef STRINGIFY
}
int TokHz(double frequency) {
delete data;
}
-void RadioInterruptedCallback(radio_interrupted_code_e code, void* user_data) {
- ScopeLogger();
-
- picojson::value event{picojson::object()};
- auto& obj = event.get<picojson::object>();
-
- obj.insert(std::make_pair("listenerId", picojson::value("FMRadio_Interrupted")));
-
- if (code == RADIO_INTERRUPTED_COMPLETED) {
- obj.insert(std::make_pair("action", picojson::value("oninterruptfinished")));
- } else {
- obj.insert(std::make_pair("action", picojson::value("oninterrupted")));
- obj.insert(std::make_pair("reason", picojson::value(TranslateInterruptedCode(code))));
- }
-
- FMRadioManager* manager = static_cast<FMRadioManager*>(user_data);
- common::TaskQueue::GetInstance().Async(
- std::bind(&FMRadioManager::PostMessage, manager, event.serialize()));
-}
-
void RadioAntennaCallback(runtime_info_key_e key, void* user_data) {
ScopeLogger();
std::bind(&FMRadioManager::PostMessage, manager, event.serialize()));
}
+void SoundStreamFocusCallback(sound_stream_info_h stream_info, sound_stream_focus_mask_e focus_mask,
+ sound_stream_focus_state_e focus_state,
+ sound_stream_focus_change_reason_e reason_for_change,
+ int sound_behavior, const char* additional_info, void* user_data) {
+ ScopeLogger("reason_for_change: %d", reason_for_change);
+
+ FMRadioManager* manager = static_cast<FMRadioManager*>(user_data);
+
+ picojson::value event{picojson::object()};
+ auto& obj = event.get<picojson::object>();
+
+ obj.insert(std::make_pair("listenerId", picojson::value("FMRadio_Interrupted")));
+
+ if (SOUND_STREAM_FOCUS_STATE_ACQUIRED != focus_state) {
+ LoggerD("Stopping radio");
+ const auto err_radio_stop = radio_stop(manager->GetRadioInstance());
+ if (RADIO_ERROR_NONE != err_radio_stop) {
+ LoggerE("Failed to stop radio: %d", err_radio_stop);
+ }
+
+ obj.insert(std::make_pair("action", picojson::value("oninterrupted")));
+ obj.insert(
+ std::make_pair("reason", picojson::value(TranslateInterruptedCode(reason_for_change))));
+ } else {
+ // As we stopped radio on first interrupt, we will release focus on second
+ LoggerD("Preparing to release focus");
+ auto release_focus = [&manager]() {
+ ScopeLogger("Entered into asynchronous function, release_focus");
+ const auto sound_focus_err = sound_manager_release_focus(
+ manager->GetStreamInfo(), SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
+ if (SOUND_MANAGER_ERROR_NONE != sound_focus_err) {
+ LoggerE("sound_manager_release_focus() failed: %d", sound_focus_err);
+ }
+ };
+ common::TaskQueue::GetInstance().Async(release_focus);
+
+ obj.insert(std::make_pair("action", picojson::value("oninterruptfinished")));
+ }
+
+ if (manager->IsInterruptedListenerSet()) {
+ common::TaskQueue::GetInstance().Async(
+ std::bind(&FMRadioManager::PostMessage, manager, event.serialize()));
+ }
+}
+
} // namespace
bool FMRadioManager::IsMuted() {
}
}
+bool FMRadioManager::IsInterruptedListenerSet() {
+ return is_interrupted_listener_set;
+}
+
+radio_h FMRadioManager::GetRadioInstance() {
+ return radio_instance_;
+};
+
+sound_stream_info_h FMRadioManager::GetStreamInfo() {
+ return stream_info_;
+}
+
PlatformResult FMRadioManager::SetFrequency(double frequency) {
ScopeLogger();
return CheckError("radio_set_frequency", radio_set_frequency(radio_instance_, TokHz(frequency)));
}
FMRadioManager::FMRadioManager(RadioInstance& instance)
- : instance_(instance), radio_instance_(nullptr), scan_data(nullptr) {
+ : instance_(instance),
+ radio_instance_(nullptr),
+ scan_data(nullptr),
+ stream_info_(nullptr),
+ is_interrupted_listener_set(false) {
ScopeLogger();
const auto err = radio_create(&radio_instance_);
LoggerE("radio_create() failed: %d", err);
radio_instance_ = nullptr;
}
+
+ const auto err_sound = sound_manager_create_stream_information(
+ SOUND_STREAM_TYPE_MEDIA, SoundStreamFocusCallback, this, &stream_info_);
+ if (SOUND_MANAGER_ERROR_NONE != err_sound) {
+ LoggerE("sound_manager_create_stream_information() failed: %d", err_sound);
+ stream_info_ = nullptr;
+ }
}
FMRadioManager::~FMRadioManager() {
LoggerE("radio_destroy() failed: %d", err);
}
}
+
+ if (nullptr != stream_info_) {
+ const auto err = sound_manager_destroy_stream_information(stream_info_);
+ if (RADIO_ERROR_NONE != err) {
+ LoggerE("sound_manager_destroy_stream_information() failed: %d", err);
+ }
+ }
+
delete scan_data;
}
if (RADIO_STATE_READY != state && RADIO_STATE_PLAYING != state) {
return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Invalid radio state.");
}
+ LoggerD("Current radio state: %d", state);
PlatformResult result = SetFrequency(frequency);
return result;
}
- if (RADIO_STATE_READY == state) {
- return CheckError("radio_start", radio_start(radio_instance_));
- } else {
- return result;
+ if (RADIO_STATE_PLAYING == state) {
+ LoggerD("Radio is already started.");
+ return PlatformResult(ErrorCode::NO_ERROR);
+ }
+ // state == RADIO_STATE_READY
+ sound_stream_focus_state_e state_for_playback;
+ sound_stream_focus_state_e state_for_recording;
+
+ const auto err_focus_state =
+ sound_manager_get_focus_state(stream_info_, &state_for_playback, &state_for_recording);
+
+ if (SOUND_MANAGER_ERROR_NONE != err_focus_state) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Checking sound focus state failed.",
+ ("sound_manager_get_focus_state failed: %d", err_focus_state));
}
+
+ if (SOUND_STREAM_FOCUS_STATE_ACQUIRED != state_for_playback) {
+ LoggerD("Current sound stream focus state: %d, acquiring focus", state_for_playback);
+ const auto err_sound_focus = sound_manager_acquire_focus(
+ stream_info_, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
+
+ if (SOUND_MANAGER_ERROR_NONE != err_sound_focus) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Acquiring sound focus failed.",
+ ("sound_manager_acquire_focus failed: %d", err_sound_focus));
+ }
+ }
+
+ return CheckError("radio_start", radio_start(radio_instance_));
}
PlatformResult FMRadioManager::Stop() {
return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Invalid radio state.");
}
- return CheckError("radio_stop", radio_stop(radio_instance_));
+ const auto err_radio_stop = radio_stop(radio_instance_);
+ const auto sound_focus_err = sound_manager_release_focus(
+ stream_info_, SOUND_STREAM_FOCUS_FOR_PLAYBACK, SOUND_BEHAVIOR_NONE, NULL);
+ if (SOUND_MANAGER_ERROR_NONE != sound_focus_err) {
+ LoggerE("sound_manager_release_focus() failed: %d", sound_focus_err);
+ }
+
+ return CheckError("radio_stop", err_radio_stop);
}
void FMRadioManager::SeekUp(double callback_id) {
common::PlatformResult FMRadioManager::SetFMRadioInterruptedListener() {
ScopeLogger();
- const auto err = radio_set_interrupted_cb(radio_instance_, RadioInterruptedCallback, this);
- return CheckError("radio_set_interrupted_cb", err);
+ is_interrupted_listener_set = true;
+ return PlatformResult(ErrorCode::NO_ERROR);
}
common::PlatformResult FMRadioManager::UnsetFMRadioInterruptedListener() {
ScopeLogger();
- const auto err = radio_unset_interrupted_cb(radio_instance_);
- return CheckError("radio_unset_interrupted_cb", err);
+ is_interrupted_listener_set = false;
+ return PlatformResult(ErrorCode::NO_ERROR);
}
common::PlatformResult FMRadioManager::SetAntennaChangeListener() {