1) web engine get current user media state from media device.
2) web engine notify webbrowser state by ewk callback.
Add new ewk type:
UserMediaState
DECLARE_EWK_VIEW_CALLBACK(UserMediaState, "usermedia,state", void*)
From patch:
https://review.tizen.org/gerrit/#/c/294421/
Change-Id: I6acab4de98627aa478017512da79f1e0520236f8
Signed-off-by: zhishun.zhou <zhishun.zhou@samsung.com>
Signed-off-by: xiaofang <fang.xiao@samsung.com>
#include "chromeos/lacros/lacros_service.h"
#endif
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
+#endif
+
using blink::mojom::MediaDeviceType;
namespace content {
device_capture_configuration_change_cb,
DeviceCaptureHandleChangeCallback device_capture_handle_change_cb) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+#if BUILDFLAG(IS_TIZEN_TV)
+ render_frame_host_id_ = render_frame_host_id;
+#endif
+
SendLogMessage(GetGenerateStreamsLogString(render_frame_host_id, requester_id,
page_request_id));
std::unique_ptr<DeviceRequest> request =
media::AudioParameters::UnavailableDeviceParams())));
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void MediaStreamManager::NotifyMediaStateChanged(uint32_t type,
+ uint32_t previous,
+ uint32_t current) {
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(
+ content::RenderFrameHost::FromID(render_frame_host_id_));
+ if (!web_contents) {
+ LOG(ERROR) << "web_contents is null";
+ return;
+ }
+
+ content::WebContentsDelegate* web_contents_delegate =
+ web_contents->GetDelegate();
+ if (!web_contents_delegate) {
+ LOG(ERROR) << "web_contents_delegate is null";
+ return;
+ }
+
+ web_contents_delegate->NotifyMediaStateChanged(type, previous, current);
+}
+#endif
void MediaStreamManager::SetUpRequest(const std::string& label) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
namespace content {
+#if BUILDFLAG(IS_TIZEN_TV)
+enum MediaInputStreamType { NO_STREAM, AUDIO_CAPTURE, VIDEO_CAPTURE };
+#endif
+
class AudioInputDeviceManager;
class AudioServiceListener;
class FakeMediaStreamUIProxy;
void NotifyDevicesChanged(blink::mojom::MediaDeviceType stream_type,
const blink::WebMediaDeviceInfoArray& devices);
+#if BUILDFLAG(IS_TIZEN_TV)
+ // Notify media(camera/microphone) status change to web browser.
+ void NotifyMediaStateChanged(uint32_t type,
+ uint32_t previous,
+ uint32_t current);
+#endif
+
// This method is called when an audio or video device is removed. It makes
// sure all MediaStreams that use a removed device are stopped and that the
// render process is notified. Must be called on the IO thread.
mojo::UniqueReceiverSet<media::mojom::VideoCaptureHost> video_capture_hosts_;
GenerateStreamTestCallback generate_stream_test_callback_;
+
+#if BUILDFLAG(IS_TIZEN_TV)
+ GlobalRenderFrameHostId render_frame_host_id_;
+#endif
};
} // namespace content
#include "third_party/blink/public/common/mediastream/media_stream_request.h"
#include "url/origin.h"
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "content/browser/browser_main_loop.h"
+#endif
+
using blink::mojom::MediaDeviceType;
namespace content {
const base::UnguessableToken& input_stream_id,
const std::string& raw_output_device_id);
+#if BUILDFLAG(IS_TIZEN_TV)
+ void OnMediaStateChanged(uint32_t previous, uint32_t current);
+ void NotifyMediaStateChanged(uint32_t previous, uint32_t current);
+#endif
+
const raw_ptr<MediaStreamManager> media_stream_manager_;
const int process_id_;
const int frame_id_;
raw_output_device_id);
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void RenderFrameAudioInputStreamFactory::Core::OnMediaStateChanged(
+ uint32_t previous,
+ uint32_t current) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&Core::NotifyMediaStateChanged,
+ weak_ptr_factory_.GetWeakPtr(), previous, current));
+}
+
+void RenderFrameAudioInputStreamFactory::Core::NotifyMediaStateChanged(
+ uint32_t previous,
+ uint32_t current) {
+ content::BrowserMainLoop* browser_main_loop =
+ content::BrowserMainLoop::GetInstance();
+ if (!browser_main_loop) {
+ LOG(ERROR) << "browser_main_loop is null";
+ return;
+ }
+ content::MediaStreamManager* msm = browser_main_loop->media_stream_manager();
+ if (!msm) {
+ LOG(ERROR) << "MediaStreamManager is null";
+ return;
+ }
+ msm->NotifyMediaStateChanged(content::MediaInputStreamType::AUDIO_CAPTURE,
+ previous, current);
+}
+#endif
} // namespace content
// Picture-in-Picture mode has ended.
virtual void ExitPictureInPicture() {}
+#if BUILDFLAG(IS_TIZEN_TV)
+ // Notify Media State to Web browser
+ virtual void NotifyMediaStateChanged(uint32_t type,
+ uint32_t previous,
+ uint32_t current) {};
+#endif
#if BUILDFLAG(IS_ANDROID)
// Updates information to determine whether a user gesture should carryover to
// future navigations. This is needed so navigations within a certain
blink::WebEncryptedMediaClient* EncryptedMediaClient() override;
blink::WebString UserAgentOverride() override;
absl::optional<blink::UserAgentMetadata> UserAgentMetadataOverride() override;
- blink::mojom::RendererAudioInputStreamFactory* GetAudioInputStreamFactory();
+ blink::mojom::RendererAudioInputStreamFactory* GetAudioInputStreamFactory()
+ override;
bool AllowContentInitiatedDataUrlNavigations(
const blink::WebURL& url) override;
void PostAccessibilityEvent(const ui::AXEvent& event) override;
enabled_features += [ "tizen_video_hole" ]
}
+ if (tizen_product_tv) {
+ enabled_features += [ "is_tizen_tv" ]
+ }
+
shared_typemaps = [
{
types = [
interface AudioInputStreamClient {
OnError(InputStreamErrorCode code);
OnMutedStateChanged(bool is_muted);
+
+ [EnableIf=is_tizen_tv]
+ OnMediaStateChanged(uint32 previous, uint32 current);
};
// An AudioInputStreamObserver gets notifications about events related to an
DCHECK(task_runner_->BelongsToCurrentThread());
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
- if (!stream_ || audio_callback_)
+ if (!stream_ || audio_callback_) {
+#if BUILDFLAG(IS_TIZEN_TV)
+ OnMediaStateChanged(AUDIO_IO_ERROR);
+#endif
return;
+ }
event_handler_->OnLog("AIC::Record()");
#endif
stream_->Start(audio_callback_.get());
+#if BUILDFLAG(IS_TIZEN_TV)
+ OnMediaStateChanged(AUDIO_IO_STARTED);
+#endif
+
return;
}
DCHECK(task_runner_->BelongsToCurrentThread());
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
- if (!stream_)
+ if (!stream_) {
+#if BUILDFLAG(IS_TIZEN_TV)
+ OnMediaStateChanged(AUDIO_IO_ERROR);
+#endif
return;
+ }
check_muted_state_timer_.AbandonAndStop();
stream_->Close();
stream_ = nullptr;
+#if BUILDFLAG(IS_TIZEN_TV)
+ OnMediaStateChanged(AUDIO_IO_STOPPED);
+#endif
+
sync_writer_->Close();
#if defined(AUDIO_POWER_MONITORING)
if (!stream) {
LogCaptureStartupResult(CAPTURE_STARTUP_CREATE_STREAM_FAILED);
event_handler_->OnError(STREAM_CREATE_ERROR);
+#if BUILDFLAG(IS_TIZEN_TV)
+ OnMediaStateChanged(AUDIO_IO_ERROR);
+#endif
return;
}
stream->Close();
LogCaptureStartupResult(CAPTURE_STARTUP_OPEN_STREAM_FAILED);
event_handler_->OnError(MapOpenOutcomeToErrorCode(open_outcome));
+#if BUILDFLAG(IS_TIZEN_TV)
+ OnMediaStateChanged(AUDIO_IO_ERROR);
+#endif
return;
}
}
#endif
+#if BUILDFLAG(IS_TIZEN_TV)
+void InputController::OnMediaStateChanged(uint32_t current_state) {
+ DCHECK_CALLED_ON_VALID_THREAD(owning_thread_);
+ if (current_state != previous_state_) {
+ LOG(INFO) << "microphone state change previous: " << previous_state_
+ << " ;current : " << current_state;
+ event_handler_->OnMediaStateChanged(previous_state_, current_state);
+ previous_state_ = current_state;
+ }
+}
+#endif
+
// static
InputController::StreamType InputController::ParamsToStreamType(
const media::AudioParameters& params) {
class DeviceOutputListener;
class ProcessingAudioFifo;
+#if BUILDFLAG(IS_TIZEN_TV)
+enum AudioIOState {
+ AUDIO_IO_IDLE,
+ AUDIO_IO_STARTED,
+ AUDIO_IO_STOPPED,
+ AUDIO_IO_ERROR
+};
+#endif
+
// Only do power monitoring for non-mobile platforms to save resources.
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)
#define AUDIO_POWER_MONITORING
virtual void OnLog(base::StringPiece) = 0;
// Called whenever the muted state of the underlying stream changes.
virtual void OnMuted(bool is_muted) = 0;
+#if BUILDFLAG(IS_TIZEN_TV)
+ virtual void OnMediaStateChanged(uint32_t previous, uint32_t current) = 0;
+#endif
protected:
virtual ~EventHandler() {}
void OnStreamActive(Snoopable* snoopable) override;
void OnStreamInactive(Snoopable* snoopable) override;
+#if BUILDFLAG(IS_TIZEN_TV)
+ void OnMediaStateChanged(uint32_t current);
+#endif
+
private:
friend class InputControllerTestHelper;
// in the AudioCallback class in the cc file.
std::unique_ptr<AudioCallback> audio_callback_;
+#if BUILDFLAG(IS_TIZEN_TV)
+ uint32_t previous_state_{AUDIO_IO_IDLE};
+#endif
+
// A weak pointer factory that we use when posting tasks to the audio thread
// that we want to be automatically discarded after Close() has been called
// and that we do not want to keep the InputController instance alive
va_end(args);
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void InputStream::OnMediaStateChanged(uint32_t previous, uint32_t current) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+ if (client_.get()) {
+ client_->OnMediaStateChanged(previous, current);
+ }
+}
+#endif
} // namespace audio
void OnLog(base::StringPiece) override;
void OnMuted(bool is_muted) override;
+#if BUILDFLAG(IS_TIZEN_TV)
+ void OnMediaStateChanged(uint32_t previous, uint32_t current) override;
+#endif
+
private:
void OnStreamError(
absl::optional<media::mojom::AudioInputStreamObserver::DisconnectReason>
void OnError(media::mojom::InputStreamErrorCode code) override;
void OnMutedStateChanged(bool is_muted) override;
+#if BUILDFLAG(IS_TIZEN_TV)
+ void OnMediaStateChanged(uint32_t previous, uint32_t current) override {}
+#endif
+
void StreamCreated(media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
bool is_muted,
const absl::optional<base::UnguessableToken>& stream_id);
AssociateInputAndOutputForAec(
mojo_base.mojom.UnguessableToken input_stream_id,
string output_device_id);
+
+ // Notify Audio device state to web browser
+ [EnableIf=is_tizen_tv]
+ OnMediaStateChanged(uint32 previous, uint32 current);
};
interface RendererAudioInputStreamFactoryClient {
#include "third_party/blink/public/mojom/frame/user_activation_update_types.mojom-shared.h"
#include "third_party/blink/public/mojom/loader/same_document_navigation_type.mojom-shared.h"
#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom-shared.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
#include "third_party/blink/public/mojom/portal/portal.mojom-shared.h"
#include "third_party/blink/public/platform/child_url_loader_factory_bundle.h"
#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
const base::UnguessableToken& input_stream_id,
const std::string& output_device_id) {}
+ virtual blink::mojom::RendererAudioInputStreamFactory*
+ GetAudioInputStreamFactory() {
+ return nullptr;
+ }
+
// Notifies the observers of the origins for which subresource redirect
// optimizations can be preloaded.
virtual void PreloadSubresourceOptimizationsForOrigins(
const media::AudioSourceParameters& source_params) {
CHECK(!source_params.session_id.is_empty());
return std::make_unique<MojoAudioInputIPC>(
- source_params,
+ frame_token, source_params,
base::BindRepeating(&CreateMojoAudioInputStream, main_task_runner,
frame_token),
base::BindRepeating(&AssociateInputAndOutputForAec, main_task_runner,
namespace blink {
MojoAudioInputIPC::MojoAudioInputIPC(
+ const blink::LocalFrameToken& frame_token,
const media::AudioSourceParameters& source_params,
StreamCreatorCB stream_creator,
StreamAssociatorCB stream_associator)
: source_params_(source_params),
+#if BUILDFLAG(IS_TIZEN_TV)
+ frame_token_(frame_token),
+#endif
stream_creator_(std::move(stream_creator)),
stream_associator_(std::move(stream_associator)) {
DETACH_FROM_SEQUENCE(sequence_checker_);
void MojoAudioInputIPC::CloseStream() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+#if BUILDFLAG(IS_TIZEN_TV)
+ auto* web_frame = static_cast<WebLocalFrame*>(
+ blink::WebFrame::FromFrameToken(frame_token_));
+ if (web_frame) {
+ web_frame->Client()->GetAudioInputStreamFactory()->OnMediaStateChanged(
+ audio_previous_state_, audio::AUDIO_IO_IDLE);
+ audio_previous_state_ = audio::AUDIO_IO_IDLE;
+ }
+#endif
+
delegate_ = nullptr;
factory_client_receiver_.reset();
stream_client_receiver_.reset();
delegate_->OnMuted(is_muted);
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void MojoAudioInputIPC::OnMediaStateChanged(uint32_t previous,
+ uint32_t current) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ auto* web_frame = static_cast<WebLocalFrame*>(
+ blink::WebFrame::FromFrameToken(frame_token_));
+ if (web_frame) {
+ audio_previous_state_ = current;
+ web_frame->Client()->GetAudioInputStreamFactory()->OnMediaStateChanged(
+ previous, current);
+ }
+}
+#endif
} // namespace blink
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom-blink.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/renderer/modules/modules_export.h"
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "services/audio/input_controller.h"
+#endif
+
namespace blink {
// MojoAudioInputIPC is a renderer-side class for handling creation,
base::RepeatingCallback<void(const base::UnguessableToken& stream_id,
const std::string& output_device_id)>;
- MojoAudioInputIPC(const media::AudioSourceParameters& source_params,
+ MojoAudioInputIPC(const blink::LocalFrameToken& frame_token,
+ const media::AudioSourceParameters& source_params,
StreamCreatorCB stream_creator,
StreamAssociatorCB stream_associator);
const absl::optional<base::UnguessableToken>& stream_id) override;
void OnError(media::mojom::InputStreamErrorCode code) override;
void OnMutedStateChanged(bool is_muted) override;
+#if BUILDFLAG(IS_TIZEN_TV)
+ void OnMediaStateChanged(uint32_t previous, uint32_t current) override;
+#endif
void OnDisconnect(uint32_t error, const std::string& reason);
SEQUENCE_CHECKER(sequence_checker_);
const media::AudioSourceParameters source_params_;
+#if BUILDFLAG(IS_TIZEN_TV)
+ const blink::LocalFrameToken frame_token_;
+ uint32_t audio_previous_state_{audio::AUDIO_IO_IDLE};
+#endif
StreamCreatorCB stream_creator_;
StreamAssociatorCB stream_associator_;
AudioBlockFifo fifo_;
private:
- AudioManagerCapi* audio_manager_;
+ AudioManagerCapi* audio_manager_{nullptr};
double volume_;
};
return camera_attr_set_stream_flip(camera_handle_, flip);
}
+#if BUILDFLAG(IS_TIZEN_TV)
+int CameraHandle::CameraSetStateChangedCb(camera_state_changed_cb callback,
+ void* data) {
+ return camera_set_state_changed_cb(camera_handle_, callback, data);
+}
+
+int CameraHandle::CameraUnSetStateChangedCb() {
+ return camera_unset_state_changed_cb(camera_handle_);
+}
+#endif
} // namespace media
CameraHandle(const CameraHandle&) = delete;
CameraHandle& operator=(const CameraHandle&) = delete;
+#if BUILDFLAG(IS_TIZEN_TV)
+ int CameraSetStateChangedCb(camera_state_changed_cb callback, void* data);
+ int CameraUnSetStateChangedCb();
+#endif
+
private:
bool GetSupportedPreviewResolutions(
std::vector<CameraCapability::Resolution>& supported_resolutions) const;
#include "ui/display/display.h"
#include "ui/display/screen.h"
+#if BUILDFLAG(IS_TIZEN_TV)
+#include "content/browser/browser_main_loop.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#endif
+
namespace gfx {
class Size;
}
}
}
+#if BUILDFLAG(IS_TIZEN_TV)
+ /* add camera status callback to webbrowser */
+ err = camera_instance_->CameraSetStateChangedCb(OnCameraStateChanged, this);
+ if (CAMERA_ERROR_NONE != err) {
+ SetErrorState(CameraHandle::GetErrorString(err), FROM_HERE);
+ return;
+ }
+#endif
+
if (IsMobileProfile() && !IsEmulatorArch() &&
(camera_instance_->GetDeviceIndex() == CAMERA_DEVICE_CAMERA1)) {
err = camera_instance_->CameraSetStreamFlip(CAMERA_FLIP_HORIZONTAL);
else
camera_instance_->CameraUnsetPreviewCb();
camera_instance_->CameraStopPreview();
+#if BUILDFLAG(IS_TIZEN_TV)
+ camera_instance_->CameraUnSetStateChangedCb();
+#endif
if (IsMobileProfile())
ReleaseDisplayLock();
SetErrorState(CameraHandle::GetErrorString(err), FROM_HERE);
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void VideoCaptureDeviceTizen::OnCameraStateChanged(camera_state_e previous,
+ camera_state_e current,
+ bool by_policy,
+ void* data) {
+ VideoCaptureDeviceTizen* video_capture_device_tizen =
+ static_cast<VideoCaptureDeviceTizen*>(data);
+ if (!video_capture_device_tizen) {
+ LOG(ERROR) << "video_capture_device_tizen is null";
+ return;
+ }
+
+ content::BrowserMainLoop* browser_main_loop =
+ content::BrowserMainLoop::GetInstance();
+ if (!browser_main_loop) {
+ LOG(ERROR) << "browser_main_loop is null";
+ return;
+ }
+ content::MediaStreamManager* msm = browser_main_loop->media_stream_manager();
+ if (!msm) {
+ LOG(ERROR) << "MediaStreamManager is null";
+ return;
+ }
+ msm->NotifyMediaStateChanged(content::MediaInputStreamType::VIDEO_CAPTURE,
+ previous, current);
+}
+#endif
} // namespace media
void* userData);
static void CaptureCompletedCb(void* userData);
+#if BUILDFLAG(IS_TIZEN_TV)
+ static void OnCameraStateChanged(camera_state_e previous,
+ camera_state_e current,
+ bool by_policy,
+ void* data);
+#endif
+
void MaybeSuspend() override;
void Resume() override;
#include "common/application_type.h"
#include "devtools_port_manager.h"
#include "public/ewk_media_downloadable_font_info.h"
+#include "public/ewk_user_media_internal.h"
#include "browser/mixed_content_observer.h"
#endif
MixedContentObserver::FromWebContents(web_contents_.get());
return mixed_content_observer->MixedContentReply(allow);
}
+
+void EWebView::NotifyMediaStateChanged(uint32_t device_type,
+ uint32_t previous,
+ uint32_t current) {
+ LOG(INFO) << "NotifyMediaStateChanged type : " << device_type
+ << " ;previous: " << previous << " ; current: " << current;
+ Ewk_User_Media_State_Info* user_media_state_info =
+ new _Ewk_User_Media_State_Info;
+ user_media_state_info->device_type =
+ static_cast<Ewk_User_Media_Device_Type>(device_type);
+ user_media_state_info->previous_state = previous;
+ user_media_state_info->current_state = current;
+ SmartCallback<EWebViewCallbacks::UserMediaState>().call(
+ static_cast<void*>(user_media_state_info));
+
+ delete user_media_state_info;
+}
#endif
bool RWIInfoShowed() { return rwi_info_showed_; }
GURL RWIURL() { return rwi_gurl_; }
void OnDialogClosed();
+ void NotifyMediaStateChanged(uint32_t type,
+ uint32_t previous,
+ uint32_t current);
#endif // IS_TIZEN_TV
void SetDidChangeThemeColorCallback(
return source;
}
+#if BUILDFLAG(IS_TIZEN_TV)
+void WebContentsDelegateEfl::NotifyMediaStateChanged(uint32_t type,
+ uint32_t previous,
+ uint32_t current) {
+ if (!web_view_) {
+ LOG(ERROR) << "web_view_ is null";
+ return;
+ }
+
+ web_view_->NotifyMediaStateChanged(type, previous, current);
+}
+#endif
+
void WebContentsDelegateEfl::NavigationStateChanged(
WebContents* source, InvalidateTypes changed_flags) {
// We always notfiy clients about title invalidation, even if its text
#if BUILDFLAG(IS_TIZEN_TV)
void UpdateTargetURL(WebContents* source, const GURL& url) override;
void ShowInspectorPortInfo();
+ void NotifyMediaStateChanged(uint32_t type,
+ uint32_t previous,
+ uint32_t current) override;
#endif
#if defined(TIZEN_AUTOFILL)