From: Hyunsoo Park Date: Tue, 6 Nov 2018 06:36:19 +0000 (+0900) Subject: Add 'R2 Secondary Sink' X-Git-Tag: submit/tizen/20190507.101459^2~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bc75646bec1faea57a9348260b4703a035c1abe3;p=platform%2Fcore%2Fapi%2Fscreen-mirroring.git Add 'R2 Secondary Sink' I added files for 'R2 Secondary Sink' function and testing. - scmirroring_secondary_sink.h - scmirroring_secondary_sink.c - scmirroring_secondary_sink_test.c Change-Id: I56d7b7b2ce9db393f3b4b3dbe852aa95cf57eeab Signed-off-by: Hyunsoo Park --- diff --git a/include/scmirroring_private.h b/include/scmirroring_private.h index bac3bbd..91a598e 100644 --- a/include/scmirroring_private.h +++ b/include/scmirroring_private.h @@ -156,6 +156,17 @@ typedef struct { char *coupled_sink_ip; } scmirroring_primary_sink_s; + +typedef struct { + MMHandleType mm_handle; + char *ip; + char *port; + bool use_hdcp; + scmirroring_sink_state_cb_s *scmirroring_sink_state_cb; + unsigned int magic_num; + char *coupled_sink_ip; +} scmirroring_secondary_sink_s; + #define WIFIDIRECT_DISPLAY_FEATURE "http://tizen.org/feature/network.wifi.direct.display" #define CHECK_FEATURE_SUPPORTED(feature_name)\ diff --git a/include/scmirroring_secondary_sink.h b/include/scmirroring_secondary_sink.h new file mode 100644 index 0000000..71c6607 --- /dev/null +++ b/include/scmirroring_secondary_sink.h @@ -0,0 +1,603 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* 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. +*/ + +#ifndef __TIZEN_MEDIA_SCMIRRORING_SECONDARY_SINK_H__ +#define __TIZEN_MEDIA_SCMIRRORING_SECONDARY_SINK_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file scmirroring_secondary_sink.h + * @brief This file contains the screen mirroring source API and functions related with screen mirroring as sink device. + */ + +/** + * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE + * @{ + */ + +/** + * @brief Creates a new screen mirroring sink handle. + * @since_tizen 2.4 + * + * @remarks You must release @a scmirroring_secondary_sink using scmirroring_secondary_sink_destroy(). + * + * @param[out] scmirroring_secondary_sink A newly returned handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_NULL + * + * @see scmirroring_secondary_sink_destroy() + */ +int scmirroring_secondary_sink_create(scmirroring_secondary_sink_h *scmirroring_secondary_sink); + +/** + * @brief Registers a callback function to be called when state change happens. + * @details This function registers user callback and this callback is called when each status is changed. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[in] callback The callback function to invoke + * @param[in] user_data The user data passed to the callback registration function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * + * @see scmirroring_secondary_sink_create() + */ +int scmirroring_secondary_sink_set_state_changed_cb(scmirroring_secondary_sink_h scmirroring_secondary_sink, scmirroring_sink_state_cb callback, void *user_data); + +/** + * @brief Sets server IP and port. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[in] ip The server IP address to connect to + * @param[in] port The server port to connect to + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * + * @see scmirroring_secondary_sink_create() + */ +int scmirroring_secondary_sink_set_ip_and_port(scmirroring_secondary_sink_h scmirroring_secondary_sink, const char *ip, const char *port); + +/** + * @brief Pass window handle created by application and surface type(x11/evas). + * @details This function will use handle created by the application to set the overlay & + * display on the surface passed by the application + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[in] type Surface type(x11/evas) + * @param[in] display_surface The display_surface created by application to force sink to display content over it + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * + * @see scmirroring_secondary_sink_create() + */ +int scmirroring_secondary_sink_set_display(scmirroring_secondary_sink_h scmirroring_secondary_sink, scmirroring_display_type_e type, void *display_surface); + +/** + * @brief Sets resolutions of screen mirroring sink. + * @details This function sets resolutions of screen mirroring sink using scmirroring_resolution_e as following. + * (ex. SCMIRRORING_RESOLUTION_1920x1080_P30 | SCMIRRORING_RESOLUTION_1280x720_P30) + * Use it only when you want to set specific resolutions but if screen mirroring source dose not support + * the resolutions which you set, the screen mirroring sink will be disconnected. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[in] resolution Resolution of screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * + * @see scmirroring_secondary_sink_create() + */ +int scmirroring_secondary_sink_set_resolution(scmirroring_secondary_sink_h scmirroring_secondary_sink, int resolution); + +/** + * @brief Prepares the screen mirroring sink handle and allocates specific resources. + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_NULL + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_PREPARED + * + * @see scmirroring_secondary_sink_create() + * @see scmirroring_secondary_sink_set_state_changed_cb() + */ +int scmirroring_secondary_sink_prepare(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Creates connection and prepare for receiving data from SCMIRRORING source. + * + * @since_tizen 2.4 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_PREPARED + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_CONNECTED + * + * @see scmirroring_secondary_sink_create() + * @see scmirroring_secondary_sink_set_state_changed_cb() + * @see scmirroring_secondary_sink_prepare() + */ +int scmirroring_secondary_sink_connect(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Starts receiving data from the SCMIRRORING source and display it(mirror). + * + * @since_tizen 2.4 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_CONNECTED + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_PLAYING + * + * @see scmirroring_secondary_sink_create() + * @see scmirroring_secondary_sink_set_state_changed_cb() + * @see scmirroring_secondary_sink_prepare() + * @see scmirroring_secondary_sink_connect() + */ +int scmirroring_secondary_sink_start(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Pauses receiving data from the SCMIRRORING source. + * @details This function pauses receiving data from the SCMIRRORING source, + * which means it sends RTSP PAUSE message to source. + * + * @since_tizen 2.4 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_PLAYING + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_PAUSED + * + * @see scmirroring_secondary_sink_create() + * @see scmirroring_secondary_sink_set_state_changed_cb() + * @see scmirroring_secondary_sink_prepare() + * @see scmirroring_secondary_sink_connect() + * @see scmirroring_secondary_sink_start() + */ +int scmirroring_secondary_sink_pause(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Resumes receiving data from the SCMIRRORING source. + * @details This function pauses receiving data from the SCMIRRORING source, which means it sends RTSP PLAY message to source. + * + * @since_tizen 2.4 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_PAUSED + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_PLAYING + * + * @see scmirroring_secondary_sink_pause() + */ +int scmirroring_secondary_sink_resume(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Disconnects and stops receiving data from the SCMIRRORING source. + * + * @since_tizen 2.4 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_CONNECTED + * or #SCMIRRORING_SINK_STATE_PLAYING or #SCMIRRORING_SINK_STATE_PAUSED + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_DISCONNECTED + * + * @see scmirroring_secondary_sink_create() + * @see scmirroring_secondary_sink_set_state_changed_cb() + * @see scmirroring_secondary_sink_prepare() + * @see scmirroring_secondary_sink_connect() + * @see scmirroring_secondary_sink_start() + */ +int scmirroring_secondary_sink_disconnect(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Unprepares screen mirroring. + * @details This function unprepares screen mirroring, which closes specific resources. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_OUT_OF_MEMORY Out of memory + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_NULL + * + * @see scmirroring_secondary_sink_create() + * @see scmirroring_secondary_sink_set_state_changed_cb() + * @see scmirroring_secondary_sink_prepare() + */ +int scmirroring_secondary_sink_unprepare(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Unregisters the callback function user registered. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * + * @see scmirroring_secondary_sink_create() + * @see scmirroring_secondary_sink_set_state_changed_cb() + */ +int scmirroring_secondary_sink_unset_state_changed_cb(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Destroys screen mirroring sink handle. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_PERMISSION_DENIED Permission denied + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_NULL + * + * @see scmirroring_secondary_sink_create() + */ +int scmirroring_secondary_sink_destroy(scmirroring_secondary_sink_h scmirroring_secondary_sink); + +/** + * @brief Gets negotiated video codec of screen mirroring sink. + * @details The video codec is negotiated by screen mirroring source. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] codec Codec of video + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ +int scmirroring_secondary_sink_get_negotiated_video_codec(scmirroring_secondary_sink_h *scmirroring_secondary_sink, scmirroring_video_codec_e *codec); + +/** + * @brief Gets negotiated video resolution of screen mirroring sink. + * @details The video resolution is negotiated by screen mirroring source. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] width Width of video + * @param[out] height Height of video + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ +int scmirroring_secondary_sink_get_negotiated_video_resolution(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *width, int *height); + +/** + * @brief Gets negotiated frame rate of screen mirroring sink. + * @details The video frame rate is negotiated by screen mirroring source. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] frame_rate Frame rate of video + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ +int scmirroring_secondary_sink_get_negotiated_video_frame_rate(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *frame_rate); + +/** + * @brief Gets negotiated audio codec of screen mirroring sink. + * @details The audio codec is negotiated by screen mirroring source. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] codec Codec of audio + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ +int scmirroring_secondary_sink_get_negotiated_audio_codec(scmirroring_secondary_sink_h *scmirroring_secondary_sink, scmirroring_audio_codec_e *codec); + +/** + * @brief Gets negotiated audio channel of screen mirroring sink. + * @details The audio channel is negotiated by screen mirroring source. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] channel Channel of audio + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ +int scmirroring_secondary_sink_get_negotiated_audio_channel(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *channel); + +/** + * @brief Gets negotiated audio sample rate of screen mirroring sink. + * @details The audio sample rate is negotiated by screen mirroring source. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] sample_rate Sample rate of audio + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ +int scmirroring_secondary_sink_get_negotiated_audio_sample_rate(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *sample_rate); + +/** + * @brief Gets negotiated audio bitwidth of screen mirroring sink. + * @details The audio bitwidth is negotiated by screen mirroring source. + * + * @since_tizen 2.4 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] bitwidth Bitwidth of audio + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + * @pre Register user callback by calling scmirroring_secondary_sink_set_state_changed_cb(). + * @pre Call scmirroring_secondary_sink_prepare() + * @pre Call scmirroring_secondary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ +int scmirroring_secondary_sink_get_negotiated_audio_bitwidth(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *bitwidth); + +/** + * @brief Gets the current state of screen mirroring sink. + * @details The current state of screen mirroring sink is changed by calling CAPIs. And it provides the state of screen mirroring sink the time this api is called. + * + * @since_tizen 5.0 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring sink + * @param[out] state The current state of screen mirroring sink + * + * @return @c 0 on success, + * otherwise a negative error value + * @retval #SCMIRRORING_ERROR_NONE Successful + * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * @retval #SCMIRRORING_ERROR_UNKNOWN Unknown Error + * + * @pre Create a screen mirroring sink handle by calling scmirroring_secondary_sink_create(). + */ +int scmirroring_secondary_sink_get_current_state(scmirroring_secondary_sink_h scmirroring_secondary_sink, scmirroring_sink_state_e *state); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/** + * @} + */ + +#endif /*__TIZEN_MEDIA_SCMIRRORING_SECONDARY_SINK_H__*/ diff --git a/packaging/capi-media-screen-mirroring.spec b/packaging/capi-media-screen-mirroring.spec index 76c8cf3..b57d858 100644 --- a/packaging/capi-media-screen-mirroring.spec +++ b/packaging/capi-media-screen-mirroring.spec @@ -1,6 +1,6 @@ Name: capi-media-screen-mirroring Summary: A screen mirroring library in Tizen C API -Version: 0.1.95 +Version: 0.1.96 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/scmirroring_secondary_sink.c b/src/scmirroring_secondary_sink.c new file mode 100644 index 0000000..139142f --- /dev/null +++ b/src/scmirroring_secondary_sink.c @@ -0,0 +1,746 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* 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 +#include + +static scmirroring_error_e __scmirroring_secondary_sink_error_convert(const char *func, int error) +{ + int ret = SCMIRRORING_ERROR_NONE; + const char *errorstr = NULL; + + switch (error) { + case MM_ERROR_NONE: + ret = SCMIRRORING_ERROR_NONE; + errorstr = "ERROR_NONE"; + break; + + case MM_ERROR_WFD_NO_FREE_SPACE: + ret = SCMIRRORING_ERROR_OUT_OF_MEMORY; + errorstr = "OUT_OF_MEMORY"; + break; + + case MM_ERROR_WFD_NOT_INITIALIZED: + case MM_ERROR_COMMON_INVALID_ATTRTYPE: + case MM_ERROR_COMMON_INVALID_PERMISSION: + case MM_ERROR_COMMON_OUT_OF_ARRAY: + case MM_ERROR_COMMON_OUT_OF_RANGE: + case MM_ERROR_COMMON_ATTR_NOT_EXIST: + ret = SCMIRRORING_ERROR_INVALID_PARAMETER; + errorstr = "INVALID_PARAMETER"; + break; + + default: + ret = SCMIRRORING_ERROR_INVALID_OPERATION; + errorstr = "INVALID_OPERATION"; + } + + if (ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("[%s] %s (0x%08x) : core frameworks error code(0x%08x)", func, errorstr, ret, error); + else + scmirroring_debug("[%s] %s", func, errorstr); + + return ret; +} + +static scmirroring_sink_state_e __SCMIRRORING_SINK_STATE_convert(MMWFDSinkStateType mm_state) +{ + scmirroring_sink_state_e state = SCMIRRORING_SINK_STATE_NONE; + + switch (mm_state) { + case MM_WFD_SINK_STATE_NONE: + state = SCMIRRORING_SINK_STATE_NONE; + break; + case MM_WFD_SINK_STATE_NULL: + state = SCMIRRORING_SINK_STATE_NULL; + break; + case MM_WFD_SINK_STATE_PREPARED: + state = SCMIRRORING_SINK_STATE_PREPARED; + break; + case MM_WFD_SINK_STATE_CONNECTED: + state = SCMIRRORING_SINK_STATE_CONNECTED; + break; + case MM_WFD_SINK_STATE_PLAYING: + state = SCMIRRORING_SINK_STATE_PLAYING; + break; + case MM_WFD_SINK_STATE_PAUSED: + state = SCMIRRORING_SINK_STATE_PAUSED; + break; + case MM_WFD_SINK_STATE_DISCONNECTED: + state = SCMIRRORING_SINK_STATE_DISCONNECTED; + break; + default: + state = SCMIRRORING_SINK_STATE_NONE; + break; + } + + return state; +} + +void __mm_scmirroring_secondary_sink_set_message_cb(int error_type, MMWFDSinkStateType state_type, void *uData) +{ + scmirroring_error_e error = __scmirroring_secondary_sink_error_convert(__func__, error_type); + scmirroring_sink_state_e state = __SCMIRRORING_SINK_STATE_convert(state_type); + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)uData; + + /* call application callback */ + if (handle && handle->scmirroring_sink_state_cb && handle->scmirroring_sink_state_cb->state_cb) + handle->scmirroring_sink_state_cb->state_cb(error, state, handle->scmirroring_sink_state_cb->user_data); + + return; +} + +int scmirroring_secondary_sink_create(scmirroring_secondary_sink_h *scmirroring_secondary_sink) +{ + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)calloc(1, sizeof(scmirroring_secondary_sink_s)); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Fail to allocate memory for handle"); + + handle->mm_handle = 0; + handle->ip = NULL; + handle->port = NULL; + handle->use_hdcp = TRUE; + handle->scmirroring_sink_state_cb = NULL; + handle->magic_num = SCMIRRORING_MAGIC_NUMBER; + + ret = mm_wfd_sink_create(&handle->mm_handle); + if (ret != MM_ERROR_NONE) { + SCMIRRORING_SAFE_FREE(handle); + scmirroring_error("Fail to Create"); + return __scmirroring_secondary_sink_error_convert(__func__, ret); + } + + *scmirroring_secondary_sink = (scmirroring_secondary_sink_h)handle; + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_set_ip_and_port(scmirroring_secondary_sink_h scmirroring_secondary_sink, const char *ip, const char *port) +{ + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + scmirroring_retvm_if(ip == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "ip is NULL"); + scmirroring_retvm_if(port == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "port is NULL"); + + scmirroring_debug("ip[%s] port[%s]", ip, port); + + SCMIRRORING_SAFE_FREE(handle->ip); + handle->ip = strdup(ip); + scmirroring_retvm_if(handle->ip == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Out of memory for ip"); + + SCMIRRORING_SAFE_FREE(handle->port); + handle->port = strdup(port); + scmirroring_retvm_if(handle->port == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Out of memory for port"); + + scmirroring_debug_fleave(); + + return SCMIRRORING_ERROR_NONE; +} + +int scmirroring_secondary_sink_prepare(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_prepare(handle->mm_handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_connect(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + char server_uri[255] = {0, }; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + if (handle->ip == NULL) { + scmirroring_error("INVALID_IP(NULL) (0x%08x)", SCMIRRORING_ERROR_INVALID_PARAMETER); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + if (handle->port == NULL) { + scmirroring_error("INVALID_PORT(NULL) (0x%08x)", SCMIRRORING_ERROR_INVALID_PARAMETER); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + memset(server_uri, 0x00, sizeof(server_uri)); + snprintf(server_uri, sizeof(server_uri), "rtsp://%s:%s/wfd1.0/streamid=0", handle->ip, handle->port); + + scmirroring_error("server_uri[%s]", server_uri); + printf("server_uri[%s]", server_uri); + + ret = mm_wfd_sink_connect(handle->mm_handle, server_uri); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_unprepare(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_unprepare(handle->mm_handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_destroy(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_destroy(handle->mm_handle); + + handle->mm_handle = 0; + handle->magic_num = 0; + SCMIRRORING_SAFE_FREE(handle->ip); + SCMIRRORING_SAFE_FREE(handle->port); + SCMIRRORING_SAFE_FREE(handle->scmirroring_sink_state_cb); + SCMIRRORING_SAFE_FREE(handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_start(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_start(handle->mm_handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_disconnect(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_disconnect(handle->mm_handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_set_state_changed_cb(scmirroring_secondary_sink_h scmirroring_secondary_sink, scmirroring_sink_state_cb callback, void *user_data) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + scmirroring_retvm_if(callback == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "callback is NULL"); + + if (handle->scmirroring_sink_state_cb == NULL) { + handle->scmirroring_sink_state_cb = (scmirroring_sink_state_cb_s *)calloc(1, sizeof(scmirroring_sink_state_cb_s)); + if (handle->scmirroring_sink_state_cb == NULL) { + scmirroring_error("Error Set CB"); + return SCMIRRORING_ERROR_OUT_OF_MEMORY; + } + } else { + memset(handle->scmirroring_sink_state_cb, 0, sizeof(scmirroring_sink_state_cb_s)); + } + + handle->scmirroring_sink_state_cb->user_data = user_data; + handle->scmirroring_sink_state_cb->state_cb = callback; + + ret = mm_wfd_sink_set_message_callback(handle->mm_handle, __mm_scmirroring_secondary_sink_set_message_cb, handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_unset_state_changed_cb(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_set_message_callback(handle->mm_handle, NULL, NULL); + + SCMIRRORING_SAFE_FREE(handle->scmirroring_sink_state_cb); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_set_display(scmirroring_secondary_sink_h scmirroring_secondary_sink, scmirroring_display_type_e type, void *display_surface) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + scmirroring_retvm_if(display_surface == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "display_surface is NULL"); + + if ((type != SCMIRRORING_DISPLAY_TYPE_OVERLAY) && (type != SCMIRRORING_DISPLAY_TYPE_EVAS)) { + scmirroring_error("Invalid display type [%d]", type); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + scmirroring_debug("display type(%d)", type); + + ret = mm_wfd_sink_set_attribute(handle->mm_handle, NULL, "display_surface_type", type, NULL); + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set Display Type"); + return __scmirroring_secondary_sink_error_convert(__func__, ret); + } + + ret = mm_wfd_sink_set_attribute(handle->mm_handle, NULL, "display_overlay", display_surface, sizeof(void *), NULL); + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set Display Overlay"); + return __scmirroring_secondary_sink_error_convert(__func__, ret); + } + + ret = mm_wfd_sink_set_attribute(handle->mm_handle, NULL, "display_visible", TRUE, NULL); + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set Display Visible as TRUE"); + return __scmirroring_secondary_sink_error_convert(__func__, ret); + } + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_set_resolution(scmirroring_secondary_sink_h scmirroring_secondary_sink, int resolution) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + if ((resolution < SCMIRRORING_RESOLUTION_UNKNOWN) || (resolution >= SCMIRRORING_RESOLUTION_MAX)) { + scmirroring_error("Invalid resolution : %d", resolution); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + scmirroring_debug("resolution(%d)", resolution); + ret = mm_wfd_sink_set_resolution(handle->mm_handle, resolution); + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set resolution"); + return __scmirroring_secondary_sink_error_convert(__func__, ret); + } + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_pause(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_pause(handle->mm_handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_resume(scmirroring_secondary_sink_h scmirroring_secondary_sink) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + ret = mm_wfd_sink_resume(handle->mm_handle); + + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_negotiated_video_codec(scmirroring_secondary_sink_h *scmirroring_secondary_sink, scmirroring_video_codec_e *codec) +{ + int ret = SCMIRRORING_ERROR_NONE; + int mm_codec = MM_WFD_SINK_VIDEO_CODEC_NONE; + + scmirroring_secondary_sink_s *handle = NULL; + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(codec == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "codec is NULL"); + + handle = (scmirroring_secondary_sink_s *)(*scmirroring_secondary_sink); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + *codec = SCMIRRORING_VIDEO_CODEC_NONE; + + ret = mm_wfd_sink_get_negotiated_video_codec(handle->mm_handle, &mm_codec); + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + switch (mm_codec) { + case MM_WFD_SINK_VIDEO_CODEC_H264: + *codec = SCMIRRORING_VIDEO_CODEC_H264; + break; + default: + *codec = SCMIRRORING_VIDEO_CODEC_NONE; + break; + } + + scmirroring_debug("codec: %d", *codec); + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_negotiated_video_resolution(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *width, int *height) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = NULL; + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(width == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "width is NULL"); + scmirroring_retvm_if(height == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "height is NULL"); + + handle = (scmirroring_secondary_sink_s *)(*scmirroring_secondary_sink); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + *width = 0; + *height = 0; + + ret = mm_wfd_sink_get_negotiated_video_resolution(handle->mm_handle, width, height); + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + scmirroring_debug("width: %d, height: %d", *width, *height); + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_negotiated_video_frame_rate(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *frame_rate) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = NULL; + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(frame_rate == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "frame_rate is NULL"); + + handle = (scmirroring_secondary_sink_s *)(*scmirroring_secondary_sink); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + *frame_rate = 0; + + ret = mm_wfd_sink_get_negotiated_video_frame_rate(handle->mm_handle, frame_rate); + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + scmirroring_debug("frame rate: %d", *frame_rate); + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_negotiated_audio_codec(scmirroring_secondary_sink_h *scmirroring_secondary_sink, scmirroring_audio_codec_e *codec) +{ + int ret = SCMIRRORING_ERROR_NONE; + int mm_codec = MM_WFD_SINK_AUDIO_CODEC_NONE; + + scmirroring_secondary_sink_s *handle = NULL; + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(codec == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "codec is NULL"); + + handle = (scmirroring_secondary_sink_s *)(*scmirroring_secondary_sink); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + *codec = SCMIRRORING_AUDIO_CODEC_NONE; + + ret = mm_wfd_sink_get_negotiated_audio_codec(handle->mm_handle, &mm_codec); + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + switch (mm_codec) { + case MM_WFD_SINK_AUDIO_CODEC_AAC: + *codec = SCMIRRORING_AUDIO_CODEC_AAC; + break; + case MM_WFD_SINK_AUDIO_CODEC_AC3: + *codec = SCMIRRORING_AUDIO_CODEC_AC3; + break; + case MM_WFD_SINK_AUDIO_CODEC_LPCM: + *codec = SCMIRRORING_AUDIO_CODEC_LPCM; + break; + default: + *codec = SCMIRRORING_AUDIO_CODEC_NONE; + break; + } + + scmirroring_debug("codec: %d", *codec); + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_negotiated_audio_channel(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *channel) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = NULL; + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(channel == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "channel is NULL"); + + handle = (scmirroring_secondary_sink_s *)(*scmirroring_secondary_sink); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + *channel = 0; + + ret = mm_wfd_sink_get_negotiated_audio_channel(handle->mm_handle, channel); + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + scmirroring_debug("channel: %d", *channel); + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_negotiated_audio_sample_rate(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *sample_rate) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = NULL; + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(sample_rate == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "sample_rate is NULL"); + + handle = (scmirroring_secondary_sink_s *)(*scmirroring_secondary_sink); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + *sample_rate = 0; + + ret = mm_wfd_sink_get_negotiated_audio_sample_rate(handle->mm_handle, sample_rate); + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + scmirroring_debug("sample rate: %d", *sample_rate); + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_negotiated_audio_bitwidth(scmirroring_secondary_sink_h *scmirroring_secondary_sink, int *bitwidth) +{ + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_secondary_sink_s *handle = NULL; + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(bitwidth == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "bitwidth is NULL"); + + handle = (scmirroring_secondary_sink_s *)(*scmirroring_secondary_sink); + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + *bitwidth = 0; + + ret = mm_wfd_sink_get_negotiated_audio_bitwidth(handle->mm_handle, bitwidth); + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + scmirroring_debug("bitwidth: %d", *bitwidth); + scmirroring_debug_fleave(); + + return ret; +} + +int scmirroring_secondary_sink_get_current_state(scmirroring_secondary_sink_h scmirroring_secondary_sink, scmirroring_sink_state_e *state) +{ + int result = MM_ERROR_NONE; + int mm_state = MM_WFD_SINK_STATE_NONE; + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)(scmirroring_secondary_sink); + + scmirroring_debug_fenter(); + scmirroring_retvm_if(scmirroring_secondary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink* is NULL"); + scmirroring_retvm_if(state == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "state is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + result = mm_wfd_sink_get_current_state(handle->mm_handle, &mm_state); + if (result == MM_ERROR_NONE) { + *state = __SCMIRRORING_SINK_STATE_convert(mm_state); + scmirroring_debug("ScreenMirroring current state is [%d]", *state); + } + scmirroring_debug_fleave(); + return __scmirroring_secondary_sink_error_convert(__func__, result); +} + +int scmirroring_secondary_sink_set_coupled_ip(scmirroring_secondary_sink_h scmirroring_secondary_sink, char* coupled_ip) +{ + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_debug_fenter(); + scmirroring_secondary_sink_s *handle = (scmirroring_secondary_sink_s *)scmirroring_secondary_sink; + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_secondary_sink is invalid handle"); + + if (coupled_ip == NULL) { + scmirroring_error("Invalid coupled ip parameter [%s]", coupled_ip); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + scmirroring_debug("coupled_ip (%s)", coupled_ip); + + ret = mm_wfd_sink_set_coupled_ip(handle->mm_handle, coupled_ip); + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set Coupled IP"); + return __scmirroring_secondary_sink_error_convert(__func__, ret); + } + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; +} + diff --git a/test_sink/scmirroring_secondary_sink_test.c b/test_sink/scmirroring_secondary_sink_test.c new file mode 100644 index 0000000..6aff3ab --- /dev/null +++ b/test_sink/scmirroring_secondary_sink_test.c @@ -0,0 +1,1199 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* 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 +#include +#include +#include +#include + +#include +#include + +#define MAX_STRING_LEN 2048 +#define SINKTEST_EXECUTE_DELAY 5000 +#define MAIN_MENU 0 +#define SUBMENU_RESOLUTION 1 +#define SUBMENU_GETTING_STREAM_INFO 2 +#define SUBMENU_SETTING_SINK 3 +#define SUBMENU_SETTING_WINDOW_SIZE 4 + +//#define TEST_WITH_WIFI_DIRECT + +#define PACKAGE "screen_mirroring_sink_test" +static int app_create(void *data); +static int app_terminate(void *data); +static Evas_Object* _create_win(const char *name); +static Evas_Object *create_evas_image_object(Evas_Object *eo_parent); +static void _win_del(void *data, Evas_Object *obj, void *event); +static gboolean _scmirroring_start_jobs(gpointer data); + +struct appcore_ops ops = { + .create = app_create, + .terminate = app_terminate, +}; +static Evas_Object* g_evas; +static Evas_Object* g_eo = NULL; + +scmirroring_secondary_sink_h g_scmirroring = NULL; +gint g_resolution = 0; +gint g_sinktype = SCMIRRORING_DISPLAY_TYPE_OVERLAY; + +gint g_menu = MAIN_MENU; + +#ifdef TEST_WITH_WIFI_DIRECT +static int g_peer_cnt = 0; +static char g_peer_ip[32]; +static char g_peer_port[32]; +static char g_src_mac_addr[18] = {0, }; +#define DEFAULT_SCREEN_MIRRORING_PORT 2022 +#endif + +gboolean __scmirroring_secondary_sink_start(gpointer data); + +#ifndef TEST_WITH_WIFI_DIRECT +static int __scmirroring_secondary_sink_create(gpointer data); +#endif +#ifdef TEST_WITH_WIFI_DIRECT +static gboolean __start_wifi_display_connection(); +static gboolean __start_p2p_connection(gpointer data); +static gboolean __disconnect_p2p_connection(void); +#endif +static void __quit_program(void); +gboolean __timeout_menu_display(void *data); + +/* Submenu for setting resolution */ +static void __display_resolution_submenu(void); +gboolean __timeout_resolution_submenu_display(void *data); +static void __interpret_resolution_submenu(char *cmd); + +/* Submenu for getting negotiated audio and video information */ +static void __display_stream_info_submenu(void); +gboolean __timeout_stream_info_submenu_display(void *data); +static void __interpret_stream_info_submenu(char *cmd); + +/* Submenu for setting sink type */ +gboolean __timeout_sink_submenu_display(void *data); +static void __display_sink_submenu(void); +static void __interpret_sink_submenu(char *cmd); +static void create_render_rect_and_bg(Evas_Object *win); + +/* Submenu for setting window size */ +gboolean __timeout_window_size_submenu_display(void *data); +static void __display_window_size_submenu(void); +static void __interpret_window_size_submenu(char *cmd); + +static void create_render_rect_and_bg(Evas_Object *win); +void create_render_rect_and_bg(Evas_Object *win) +{ + if (!win) { + g_print("no win"); + return; + } + Evas_Object *bg, *rect; + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + rect = evas_object_rectangle_add(evas_object_evas_get(win)); + if (!rect) { + g_print("no rect"); + return; + } + evas_object_color_set(rect, 0, 0, 0, 0); + evas_object_render_op_set(rect, EVAS_RENDER_COPY); + + elm_win_resize_object_add(win, rect); + evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(rect); + evas_object_show(win); +} + +static void _win_del(void *data, Evas_Object *obj, void *event) +{ + elm_exit(); +} + + +static Evas_Object* _create_win(const char *name) +{ + Evas_Object *eo = NULL; + int w = 0; + int h = 0; + + g_printf("[%s][%d] name=%s\n", __func__, __LINE__, name); + + eo = elm_win_add(NULL, name, ELM_WIN_BASIC); + if (eo) { + elm_win_title_set(eo, name); + elm_win_borderless_set(eo, EINA_TRUE); + evas_object_smart_callback_add(eo, "delete,request", _win_del, NULL); + elm_win_autodel_set(eo, EINA_TRUE); + elm_win_screen_size_get(eo, NULL, NULL, &w, &h); + g_print("window size :%d,%d\n", w, h); + elm_win_alpha_set(eo, EINA_TRUE); + } + return eo; +} + +static Evas_Object *create_evas_image_object(Evas_Object *eo_parent) +{ + if (!eo_parent) + return NULL; + + Evas *evas = evas_object_evas_get(eo_parent); + Evas_Object *eo = NULL; + + eo = evas_object_image_add(evas); + + return eo; +} + +static int app_create(void *data) +{ + + gboolean result = FALSE; + + g_print("app_create enter"); + + Evas_Object *win = NULL; + /* create window */ + win = _create_win(PACKAGE); + if (win == NULL) + return -1; + g_evas = win; + create_render_rect_and_bg(g_evas); + + elm_win_activate(win); + evas_object_show(win); + + result = _scmirroring_start_jobs((void *)NULL); + if (result != TRUE) + g_print("failed _scmirroring_start_jobs "); + + g_print("app_create leave"); + + return result; + +} +static int app_terminate(void *data) +{ + + if (g_evas) { + evas_object_del(g_evas); + g_evas = NULL; + } + return 0; +} + +gboolean __timeout_sink_submenu_display(void *data) +{ + __display_sink_submenu(); + return FALSE; +} + +static void __display_sink_submenu(void) +{ + g_print("\n"); + g_print("**********************************************************************\n"); + g_print(" Setting sink \n"); + g_print("**********************************************************************\n"); + g_print("1 : SCMIRRORING_DISPLAY_TYPE_OVERLAY with No Surface(DEFAULT)\n"); + g_print("2 : SCMIRRORING_DISPLAY_TYPE_OVERLAY with Surface\n"); + g_print("3 : SCMIRRORING_DISPLAY_TYPE_EVAS\n"); + g_print("g : Go back to main menu \n"); + g_print("**********************************************************************\n"); + +} + +static void __interpret_sink_submenu(char *cmd) +{ + if (strncmp(cmd, "1", 1) == 0) { + g_print("SCMIRRORING_DISPLAY_TYPE_OVERLAY with No Surface\n"); + g_sinktype = -1; + } else if (strncmp(cmd, "2", 1) == 0) { + g_print("SCMIRRORING_DISPLAY_TYPE_OVERLAY with Surface\n"); + g_sinktype = SCMIRRORING_DISPLAY_TYPE_OVERLAY; + } else if (strncmp(cmd, "3", 1) == 0) { + g_print("SCMIRRORING_DISPLAY_TYPE_EVAS\n"); + g_sinktype = SCMIRRORING_DISPLAY_TYPE_EVAS; + } else if (strncmp(cmd, "g", 1) == 0) { + g_print("go back to main menu\n"); + g_menu = MAIN_MENU; + g_timeout_add(100, __timeout_menu_display, 0); + return; + } + + g_print("sink type : %d\n", g_sinktype); + g_timeout_add(100, __timeout_sink_submenu_display, 0); + return; +} + +gboolean __timeout_resolution_submenu_display(void *data) +{ + __display_resolution_submenu(); + return FALSE; +} + +static void __display_resolution_submenu(void) +{ + g_print("\n"); + g_print("**********************************************************************\n"); + g_print(" Setting resolution \n"); + g_print("**********************************************************************\n"); + g_print("1 : SCMIRRORING_RESOLUTION_1920x1080_P30 [%d]\n", SCMIRRORING_RESOLUTION_1920x1080_P30); + g_print("2 : SCMIRRORING_RESOLUTION_1280x720_P30 [%d]\n", SCMIRRORING_RESOLUTION_1280x720_P30); + g_print("3 : SCMIRRORING_RESOLUTION_960x540_P30 [%d]\n", SCMIRRORING_RESOLUTION_960x540_P30); + g_print("4 : SCMIRRORING_RESOLUTION_864x480_P30 [%d]\n", SCMIRRORING_RESOLUTION_864x480_P30); + g_print("5 : SCMIRRORING_RESOLUTION_720x480_P60 [%d]\n", SCMIRRORING_RESOLUTION_720x480_P60); + g_print("6 : SCMIRRORING_RESOLUTION_640x480_P60 [%d]\n", SCMIRRORING_RESOLUTION_640x480_P60); + g_print("7 : SCMIRRORING_RESOLUTION_640x360_P30 [%d]\n", SCMIRRORING_RESOLUTION_640x360_P30); + g_print("r : Reset resolution \n"); + g_print("g : Go back to main menu \n"); + g_print("**********************************************************************\n"); + +} + +static void __interpret_resolution_submenu(char *cmd) +{ + if (strncmp(cmd, "1", 1) == 0) { + g_print("resolution |= SCMIRRORING_RESOLUTION_1920x1080_P30[%d]\n", SCMIRRORING_RESOLUTION_1920x1080_P30); + g_resolution |= SCMIRRORING_RESOLUTION_1920x1080_P30; + } else if (strncmp(cmd, "2", 1) == 0) { + g_print("resolution |= SCMIRRORING_RESOLUTION_1280x720_P30[%d]\n", SCMIRRORING_RESOLUTION_1280x720_P30); + g_resolution |= SCMIRRORING_RESOLUTION_1280x720_P30; + } else if (strncmp(cmd, "3", 1) == 0) { + g_print("resolution |= SCMIRRORING_RESOLUTION_960x540_P30[%d]\n", SCMIRRORING_RESOLUTION_960x540_P30); + g_resolution |= SCMIRRORING_RESOLUTION_960x540_P30; + } else if (strncmp(cmd, "4", 1) == 0) { + g_print("resolution |= SCMIRRORING_RESOLUTION_864x480_P30[%d]\n", SCMIRRORING_RESOLUTION_864x480_P30); + g_resolution |= SCMIRRORING_RESOLUTION_864x480_P30; + } else if (strncmp(cmd, "5", 1) == 0) { + g_print("resolution |= SCMIRRORING_RESOLUTION_720x480_P60[%d]\n", SCMIRRORING_RESOLUTION_720x480_P60); + g_resolution |= SCMIRRORING_RESOLUTION_720x480_P60; + } else if (strncmp(cmd, "6", 1) == 0) { + g_print("resolution |= SCMIRRORING_RESOLUTION_640x480_P60[%d]\n", SCMIRRORING_RESOLUTION_640x480_P60); + g_resolution |= SCMIRRORING_RESOLUTION_640x480_P60; + } else if (strncmp(cmd, "7", 1) == 0) { + g_print("resolution |= SCMIRRORING_RESOLUTION_640x360_P30[%d]\n", SCMIRRORING_RESOLUTION_640x360_P30); + g_resolution |= SCMIRRORING_RESOLUTION_640x360_P30; + } else if (strncmp(cmd, "r", 1) == 0) { + g_resolution = 0; + } else if (strncmp(cmd, "g", 1) == 0) { + g_print("go back to main menu\n"); + g_menu = MAIN_MENU; + g_timeout_add(100, __timeout_menu_display, 0); + return; + } + + g_print("resolution : %d\n", g_resolution); + + g_timeout_add(100, __timeout_resolution_submenu_display, 0); + + return; +} + +gboolean __timeout_stream_info_submenu_display(void *data) +{ + __display_stream_info_submenu(); + return FALSE; +} + +static void __display_stream_info_submenu(void) +{ + g_print("\n"); + g_print("**********************************************************************\n"); + g_print(" Getting negotiated audio and video information \n"); + g_print("**********************************************************************\n"); + g_print("1 : video codec\n"); + g_print("2 : video resolution\n"); + g_print("3 : video frame rate\n"); + g_print("4 : audio codec\n"); + g_print("5 : audio channel\n"); + g_print("6 : audio sample rate\n"); + g_print("7 : audio bitwidth\n"); + g_print("g : Go back to main menu \n"); + g_print("**********************************************************************\n"); + +} + +static void __interpret_stream_info_submenu(char *cmd) +{ + int ret = SCMIRRORING_ERROR_NONE; + if (strncmp(cmd, "1", 1) == 0) { + + scmirroring_video_codec_e codec; + ret = scmirroring_secondary_sink_get_negotiated_video_codec(&g_scmirroring, &codec); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("Error : scmirroring_secondary_sink_get_negotiated_video_codec fail[%d]\n", ret); + } else { + switch (codec) { + case SCMIRRORING_VIDEO_CODEC_H264: + g_print("video codec : H264[%d]\n", codec); + break; + default: + g_print("video codec : NONE[%d]\n", codec); + break; + } + } + + } else if (strncmp(cmd, "2", 1) == 0) { + + int width, height; + ret = scmirroring_secondary_sink_get_negotiated_video_resolution(&g_scmirroring, &width, &height); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_secondary_sink_get_negotiated_video_resolution fail[%d]\n", ret); + else + g_print("video resoltuion : width[%d], height[%d]\n", width, height); + + } else if (strncmp(cmd, "3", 1) == 0) { + + int frame_rate; + ret = scmirroring_secondary_sink_get_negotiated_video_frame_rate(&g_scmirroring, &frame_rate); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_secondary_sink_get_negotiated_video_frame_rate fail[%d]\n", ret); + else + g_print("video frame rate[%d]\n", frame_rate); + + } else if (strncmp(cmd, "4", 1) == 0) { + scmirroring_audio_codec_e codec; + ret = scmirroring_secondary_sink_get_negotiated_audio_codec(&g_scmirroring, &codec); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("Error : scmirroring_secondary_sink_get_negotiated_audio_codec fail[%d]\n", ret); + } else { + switch (codec) { + case SCMIRRORING_AUDIO_CODEC_AAC: + g_print("audio codec : AAC[%d]\n", codec); + break; + case SCMIRRORING_AUDIO_CODEC_AC3: + g_print("audio codec : AC3[%d]\n", codec); + break; + case SCMIRRORING_AUDIO_CODEC_LPCM: + g_print("audio codec : LPCM[%d]\n", codec); + break; + default: + g_print("audio codec : NONE[%d]\n", codec); + break; + } + } + + } else if (strncmp(cmd, "5", 1) == 0) { + int channel; + ret = scmirroring_secondary_sink_get_negotiated_audio_channel(&g_scmirroring, &channel); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_secondary_sink_get_negotiated_audio_channel fail[%d]\n", ret); + else + g_print("audio channel[%d]\n", channel); + + } else if (strncmp(cmd, "6", 1) == 0) { + int sample_rate; + ret = scmirroring_secondary_sink_get_negotiated_audio_sample_rate(&g_scmirroring, &sample_rate); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_secondary_sink_get_negotiated_audio_sample_rate fail[%d]\n", ret); + else + g_print("audio sample rate[%d]\n", sample_rate); + + } else if (strncmp(cmd, "7", 1) == 0) { + int bitwidth; + ret = scmirroring_secondary_sink_get_negotiated_audio_bitwidth(&g_scmirroring, &bitwidth); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_secondary_sink_get_negotiated_audio_bitwidth fail[%d]\n", ret); + else + g_print("audio bitwidth[%d]\n", bitwidth); + + } else if (strncmp(cmd, "g", 1) == 0) { + g_print("go back to main menu\n"); + g_menu = MAIN_MENU; + g_timeout_add(100, __timeout_menu_display, 0); + return; + } + + g_timeout_add(100, __timeout_stream_info_submenu_display, 0); + + return; +} + +gboolean __timeout_window_size_submenu_display(void *data) +{ + __display_window_size_submenu(); + return FALSE; + +} + +static void __display_window_size_submenu(void) +{ + g_print("\n"); + g_print("**********************************************************************\n"); + g_print(" Setting window size \n"); + g_print("**********************************************************************\n"); + g_print("1 : UHD [width:3840, height:2160] \n"); + g_print("2 : FHD [width:1920, height:1080] \n"); + g_print("3 : HD [width:1280, height:720] \n"); + g_print("g : Go back to main menu \n"); + g_print("**********************************************************************\n"); + +} + +static void __interpret_window_size_submenu(char *cmd) +{ + int w = 0; + int h = 0; + if (strncmp(cmd, "1", 1) == 0) { + w = 3840; + h = 2160; + elm_win_aux_hint_add(g_evas, "wm.policy.win.user.geometry", "1"); + evas_object_resize(g_evas, w, h); + g_print("Window size is changed.[width:%d, height:%d]", w, h); + } else if (strncmp(cmd, "2", 1) == 0) { + w = 1920; + h = 1080; + elm_win_aux_hint_add(g_evas, "wm.policy.win.user.geometry", "1"); + evas_object_resize(g_evas, w, h); + g_print("Window size is changed.[width:%d, height:%d]", w, h); + } else if (strncmp(cmd, "3", 1) == 0) { + w = 1280; + h = 720; + elm_win_aux_hint_add(g_evas, "wm.policy.win.user.geometry", "1"); + evas_object_resize(g_evas, w, h); + g_print("Window size is changed.[width:%d, height:%d]", w, h); + } else if (strncmp(cmd, "g", 1) == 0) { + g_print("go back to main menu\n"); + g_menu = MAIN_MENU; + g_timeout_add(100, __timeout_menu_display, 0); + return; + } + + g_timeout_add(100, __timeout_window_size_submenu_display, 0); + return; +} + + +static void scmirroring_sink_state_callback(scmirroring_error_e error_code, scmirroring_sink_state_e state, void *user_data) +{ + g_print("Received Callback error code[%d]", error_code); + + if (state == SCMIRRORING_SINK_STATE_NONE) + g_print(" state[%d] SCMIRRORING_SINK_STATE_NONE\n", state); + else if (state == SCMIRRORING_SINK_STATE_NULL) + g_print(" state[%d] SCMIRRORING_SINK_STATE_NULL\n", state); + else if (state == SCMIRRORING_SINK_STATE_PREPARED) + g_print(" state[%d] SCMIRRORING_SINK_STATE_PREPARED\n", state); + else if (state == SCMIRRORING_SINK_STATE_CONNECTED) { + + g_print(" state[%d] SCMIRRORING_SINK_STATE_CONNECTED\n", state); + if (scmirroring_secondary_sink_start(g_scmirroring) != SCMIRRORING_ERROR_NONE) + g_print("scmirroring_secondary_sink_start fail"); + + } else if (state == SCMIRRORING_SINK_STATE_PLAYING) + g_print(" state[%d] SCMIRRORING_SINK_STATE_PLAYING\n", state); + else if (state == SCMIRRORING_SINK_STATE_PAUSED) + g_print(" state[%d] SCMIRRORING_SINK_STATE_PAUSED\n", state); + else if (state == SCMIRRORING_SINK_STATE_DISCONNECTED) { + g_print(" state[%d] SCMIRRORING_SINK_STATE_DISCONNECTED\n", state); + if (scmirroring_secondary_sink_unprepare(g_scmirroring) != SCMIRRORING_ERROR_NONE) + g_print("scmirroring_secondary_sink_unprepare fail\n"); + if (scmirroring_secondary_sink_destroy(g_scmirroring) != SCMIRRORING_ERROR_NONE) + g_print("scmirroring_secondary_sink_destroy fail\n"); + __quit_program(); + } else + g_print(" state[%d] Invalid State", state); + + return; +} + +static void __quit_program(void) +{ + g_print("Quit Program\n"); + +#ifdef TEST_WITH_WIFI_DIRECT + __disconnect_p2p_connection(); +#endif + g_scmirroring = 0; + elm_exit(); +} + +static void __displaymenu(void) +{ + g_print("\n"); + g_print("=====================================================================\n"); + g_print(" SCMIRRORING Sink Testsuite(press q to quit) \n"); + g_print("=====================================================================\n"); +#ifndef TEST_WITH_WIFI_DIRECT + g_print("a : a ip port(ex. a 192.168.49.1 2022)\n"); + g_print("s : start\n"); +#else + g_print("b : Connecting and Starting sink with mac address which you wanna connect src device. (ex. b f8:d0:bd:7f:e9:7c)\n"); +#endif + g_print("P : Pause\n"); + g_print("R : Resume\n"); + g_print("D : Disconnect\n"); + g_print("T : desTroy\n"); + g_print("L : Setting resolution\n"); + g_print("G : Getting negotiated audio and video information\n"); + g_print("S : Setting Sink\n"); + g_print("C : Setting window size\n"); + g_print("q : quit\n"); + g_print("-----------------------------------------------------------------------------------------\n"); +} + +gboolean __timeout_menu_display(void *data) +{ + __displaymenu(); + + return FALSE; +} + +#ifdef TEST_WITH_WIFI_DIRECT +bool _connected_peer_cb(wifi_direct_connected_peer_info_s *peer, void *user_data) +{ + int peer_port = 0; + if (wifi_direct_get_peer_display_port(peer->mac_address, &peer_port) != WIFI_DIRECT_ERROR_NONE) { + g_print("Can not get port info\n Use default(2022)\n"); + peer_port = DEFAULT_SCREEN_MIRRORING_PORT; + } + if (peer_port == 0) { + g_print("Can not get port info\n Use default(2022)\n"); + peer_port = DEFAULT_SCREEN_MIRRORING_PORT; + } + + g_print("[_connected_peer_cb] Connected to IP [%s]\n", peer->ip_address); + g_print("[_connected_peer_cb] Connected to Port [%d]\n", peer_port); + g_print("[_connected_peer_cb] Connected device_name [%s]\n", peer->device_name); + g_print("[_connected_peer_cb] Connected to mac_address [%s]\n", peer->mac_address); + g_print("[_connected_peer_cb] Connected to interface_address [%s]\n", peer->interface_address); + + memset(g_peer_ip, 0x00, sizeof(g_peer_ip)); + memset(g_peer_port, 0x00, sizeof(g_peer_port)); + + snprintf(g_peer_ip, sizeof(g_peer_port), "%s", peer->ip_address); + snprintf(g_peer_port, sizeof(g_peer_port), "%d", peer_port); + + g_timeout_add(SINKTEST_EXECUTE_DELAY, __scmirroring_secondary_sink_start, NULL); + + return TRUE; +} + +void _activation_cb(int error_code, wifi_direct_device_state_e device_state, void *user_data) +{ + gint ret = FALSE; + switch (device_state) { + case WIFI_DIRECT_DEVICE_STATE_ACTIVATED: + g_print("device_state : WIFI_DIRECT_DEVICE_STATE_ACTIVATED\n"); + ret = __start_wifi_display_connection(); + if (ret == TRUE) { + g_print("__start_wifi_display_connection success\n"); + } else { + g_print("__start_wifi_display_connection fail\n"); + g_print("Quit Program\n"); + ret = wifi_direct_deinitialize(); + if (ret != WIFI_DIRECT_ERROR_NONE) + g_print("wifi_direct_deinitialize is failed\n"); + + g_scmirroring = 0; + elm_exit(); + } + break; + case WIFI_DIRECT_DEVICE_STATE_DEACTIVATED: + g_print("device_state : WIFI_DIRECT_DEVICE_STATE_DEACTIVATED\n"); + break; + default: + g_print("device_state : ERROR\n"); + break; + } + + return; +} + +bool _discovered_peer_cb(wifi_direct_discovered_peer_info_s *peer, void *user_data) +{ + g_print("[%d] discovered device peer : %s, %s, %d\n", g_peer_cnt, peer->device_name, peer->mac_address, peer->is_connected); + + g_peer_cnt++; + + return TRUE; +} + +void _discover_cb(int error_code, wifi_direct_discovery_state_e discovery_state, void *user_data) +{ + int ret = WIFI_DIRECT_ERROR_NONE; + /*g_print("Discovered [ error : %d discovery state : %d ]\n", error_code, discovery_state); */ + + switch (discovery_state) { + case WIFI_DIRECT_ONLY_LISTEN_STARTED: + g_print("discovery_state : WIFI_DIRECT_ONLY_LISTEN_STARTED \n"); + break; + case WIFI_DIRECT_DISCOVERY_STARTED: + g_print("discovery_state : WIFI_DIRECT_DISCOVERY_STARTED \n"); + break; + case WIFI_DIRECT_DISCOVERY_FOUND: + g_print("discovery_state : WIFI_DIRECT_DISCOVERY_FOUND \n"); + ret = wifi_direct_foreach_discovered_peers(_discovered_peer_cb, (void *)NULL); + if (ret != WIFI_DIRECT_ERROR_NONE) + g_print("Error : wifi_direct_foreach_discovered_peers failed : %d\n", ret); + break; + case WIFI_DIRECT_DISCOVERY_FINISHED: + g_print("discovery_state : WIFI_DIRECT_DISCOVERY_FINISHED \n"); + break; + default: + g_print("discovery_state : ERROR\n"); + break; + } + + return; +} + +void _ip_assigned_cb(const char *mac_address, const char *ip_address, const char *interface_address, void *user_data) +{ + g_print("[_ip_assigned_cb] IP assigned [ ip addr : %s if addr : %s mac_addr:%s ]\n", ip_address, interface_address, mac_address); + + int peer_port = 0; + wifi_direct_discovered_peer_info_s *peer_info = NULL; + + if (wifi_direct_get_peer_display_port((char *)mac_address, &peer_port) != WIFI_DIRECT_ERROR_NONE) { + g_print("Can not get port info\n Use default(2022)\n"); + peer_port = DEFAULT_SCREEN_MIRRORING_PORT; + } + if (peer_port == 0) { + g_print("Can not get port info\n Use default(2022)\n"); + peer_port = DEFAULT_SCREEN_MIRRORING_PORT; + } + if (wifi_direct_get_peer_info((char *)mac_address, &peer_info) != WIFI_DIRECT_ERROR_NONE) + g_print("Can not get peer info and device name\n"); + + if (peer_info != NULL && peer_info->device_name != NULL) + g_print("[_ip_assigned_cb] Connected to device_name [%s]\n", peer_info->device_name); + + g_print("[_ip_assigned_cb] Connected to IP [%s]\n", ip_address); + g_print("[_ip_assigned_cb] Connected to Port [%d]\n", peer_port); + g_print("[_ip_assigned_cb] Connected to mac_address [%s]\n", mac_address); + g_print("[_ip_assigned_cb] Connected to interface_address [%s]\n", interface_address); + + memset(g_peer_ip, 0x00, sizeof(g_peer_ip)); + memset(g_peer_port, 0x00, sizeof(g_peer_port)); + + snprintf(g_peer_ip, sizeof(g_peer_port), "%s", ip_address); + snprintf(g_peer_port, sizeof(g_peer_port), "%d", peer_port); + + g_timeout_add(SINKTEST_EXECUTE_DELAY, __scmirroring_secondary_sink_start, NULL); +} + +void _connection_cb(int error_code, wifi_direct_connection_state_e connection_state, const char *mac_address, void *user_data) +{ + int ret = WIFI_DIRECT_ERROR_NONE; + + g_print("Connected [ error : %d connection state : %d mac_addr:%s ]\n", error_code, connection_state, mac_address); + + switch (connection_state) { + case WIFI_DIRECT_CONNECTION_REQ: + g_print("WIFI_DIRECT_CONNECTION_REQ : Connection is requested\n"); + ret = wifi_direct_accept_connection((char *)mac_address); + if (ret != WIFI_DIRECT_ERROR_NONE) + g_print("Error : wifi_direct_accept_connection failed : %d\n", ret); + break; + case WIFI_DIRECT_CONNECTION_WPS_REQ: + g_print("WIFI_DIRECT_CONNECTION_WPS_REQ : WPS is requested\n"); + break; + case WIFI_DIRECT_CONNECTION_IN_PROGRESS: + g_print("WIFI_DIRECT_CONNECTION_IN_PROGRESS : Connection in progress\n"); + break; + case WIFI_DIRECT_CONNECTION_RSP: + { + bool is_go = FALSE; + g_print("WIFI_DIRECT_CONNECTION_RSP : Connected\n"); + ret = wifi_direct_is_group_owner(&is_go); + if (ret != WIFI_DIRECT_ERROR_NONE) + g_print("Error : wifi_direct_is_group_owner failed : %d\n", ret); + + if (is_go) { + g_print("Connected as Group Owner\n"); + } else { + ret = wifi_direct_foreach_connected_peers(_connected_peer_cb, (void *)NULL); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_foreach_connected_peers failed : %d\n", ret); + return; + } + g_print("Connected as Group Client\n"); + } + break; + } + case WIFI_DIRECT_DISASSOCIATION_IND: + g_print("WIFI_DIRECT_DISASSOCIATION_IND : Disconnected by remote Group Client\n"); + break; + case WIFI_DIRECT_DISCONNECTION_RSP: + g_print("WIFI_DIRECT_DISCONNECTION_RSP : Disconnected by local device\n"); + break; + case WIFI_DIRECT_DISCONNECTION_IND: + g_print("WIFI_DIRECT_DISCONNECTION_IND : Disconnected by remote Group Owner\n"); + break; + case WIFI_DIRECT_GROUP_CREATED: + g_print("WIFI_DIRECT_GROUP_CREATED : Group is created\n"); + break; + case WIFI_DIRECT_GROUP_DESTROYED: + g_print("WIFI_DIRECT_GROUP_DESTROYED : Group is destroyed\n"); + break; + default: + break; + } + return; +} + + +static int __wifi_direct_device_connect() +{ + if (strlen(g_src_mac_addr) > 17 || strlen(g_src_mac_addr) <= 0) { + g_print("\nWrong Mac_address"); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + int err = wifi_direct_connect(g_src_mac_addr); + if (err != WIFI_DIRECT_ERROR_NONE) { + g_print("Failed to connect [%d]\n", err); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + return SCMIRRORING_ERROR_NONE; +} + +#endif + +static void __interpret(char *cmd) +{ + int ret = SCMIRRORING_ERROR_NONE; + gchar **value; + value = g_strsplit(cmd, " ", 0); + + if (strncmp(cmd, "D", 1) == 0) { + g_print("Disconnect\n"); + ret = scmirroring_secondary_sink_disconnect(g_scmirroring); + } else if (strncmp(cmd, "P", 1) == 0) { + g_print("Pause\n"); + ret = scmirroring_secondary_sink_pause(g_scmirroring); + } else if (strncmp(cmd, "R", 1) == 0) { + g_print("Resume\n"); + ret = scmirroring_secondary_sink_resume(g_scmirroring); + } else if (strncmp(cmd, "T", 1) == 0) { + g_print("Destroy\n"); + ret = scmirroring_secondary_sink_unprepare(g_scmirroring); + ret = scmirroring_secondary_sink_destroy(g_scmirroring); + } else if (strncmp(cmd, "q", 1) == 0) { + __quit_program(); + } else if (strncmp(cmd, "S", 1) == 0) { + g_menu = SUBMENU_SETTING_SINK; + g_timeout_add(100, __timeout_sink_submenu_display, 0); + return; + } else if (strncmp(cmd, "L", 1) == 0) { + g_menu = SUBMENU_RESOLUTION; + g_timeout_add(100, __timeout_resolution_submenu_display, 0); + return; + } else if (strncmp(cmd, "G", 1) == 0) { + g_menu = SUBMENU_GETTING_STREAM_INFO; + g_timeout_add(100, __timeout_stream_info_submenu_display, 0); + return; + } else if (strncmp(cmd, "C", 1) == 0) { + g_menu = SUBMENU_SETTING_WINDOW_SIZE; + g_timeout_add(100, __timeout_window_size_submenu_display, 0); + return; + } +#ifndef TEST_WITH_WIFI_DIRECT + else if (strncmp(cmd, "a", 1) == 0) { + ret = __scmirroring_secondary_sink_create(NULL); + if (ret == SCMIRRORING_ERROR_NONE) { + ret = scmirroring_secondary_sink_set_ip_and_port(g_scmirroring, value[1], value[2]); + g_print("Input server IP and port number IP[%s] Port[%s]\n", value[1], value[2]); + } + } else if (strncmp(cmd, "s", 1) == 0) { + g_print("Start\n"); + ret = __scmirroring_secondary_sink_start(NULL); + } +#else + else if (strncmp(cmd, "b", 1) == 0) { + strncpy(g_src_mac_addr, value[1], sizeof(g_src_mac_addr)); + g_src_mac_addr[17] = '\0'; + g_print("Src mac address : %s\n", g_src_mac_addr); + ret = __wifi_direct_device_connect(); + } +#endif + else + g_print("unknown menu \n"); + + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error Occured [%d]", ret); + + g_timeout_add(100, __timeout_menu_display, 0); + + return; +} + +gboolean __input(GIOChannel *channel) +{ + char buf[MAX_STRING_LEN + 3]; + gsize read; + GError *error = NULL; + + g_io_channel_read_chars(channel, buf, MAX_STRING_LEN, &read, &error); + buf[read] = '\0'; + g_strstrip(buf); + + if (g_menu == MAIN_MENU) + __interpret(buf); + else if (g_menu == SUBMENU_RESOLUTION) + __interpret_resolution_submenu(buf); + else if (g_menu == SUBMENU_GETTING_STREAM_INFO) + __interpret_stream_info_submenu(buf); + else if (g_menu == SUBMENU_SETTING_SINK) + __interpret_sink_submenu(buf); + else if (g_menu == SUBMENU_SETTING_WINDOW_SIZE) + __interpret_window_size_submenu(buf); + + return TRUE; +} + +#ifdef TEST_WITH_WIFI_DIRECT +static gboolean __start_wifi_display_connection() +{ + int go_intent = 0; + static int is_initialized = FALSE; + wifi_direct_state_e direct_state = WIFI_DIRECT_STATE_DEACTIVATED; + gint ret = FALSE; + + if (is_initialized == TRUE) + return TRUE; + is_initialized = TRUE; + + /*Enable Screen Mirroring*/ + ret = wifi_direct_init_display(); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_display_init failed : %d\n", ret); + return FALSE; + } + + /*Enable Wifi Direct - You can set this as true if you want to see it from wifi-direct list*/ + ret = wifi_direct_set_display_availability(TRUE); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_display_init failed : %d\n", ret); + return FALSE; + } + + ret = wifi_direct_set_display(WIFI_DISPLAY_TYPE_SINK, 2022, 0); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_display_set_device failed : %d\n", ret); + return FALSE; + } + + ret = wifi_direct_get_group_owner_intent(&go_intent); + g_print("go_intent = [%d]\n", go_intent); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_get_group_owner_intent failed : %d\n", ret); + return FALSE; + } + + go_intent = 1; + ret = wifi_direct_set_group_owner_intent(go_intent); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_get_group_owner_intent failed : %d\n", ret); + return FALSE; + } + g_print("wifi_direct_set_group_owner_intent() result=[%d] go_intent[%d]\n", ret, go_intent); + + ret = wifi_direct_set_max_clients(1); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_set_max_clients failed : %d\n", ret); + return FALSE; + } + + ret = wifi_direct_get_state(&direct_state); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_get_state failed : %d\n", ret); + return FALSE; + } + + if (direct_state > WIFI_DIRECT_STATE_ACTIVATING) { + char *device_name = NULL; + + ret = wifi_direct_start_discovery(0, 20); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_start_discovery failed : %d\n", ret); + return FALSE; + } + + ret = wifi_direct_get_device_name(&device_name); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_get_device_name failed : %d\n", ret); + return FALSE; + } + + g_print("Device Name : [%s]\n", device_name); + if (device_name) + free(device_name); + + } else { + g_print("Error : Direct not activated yet\n"); + } + + g_print("====== p2p connection established ======\n"); + + return TRUE; +} + + +static gboolean __start_p2p_connection(gpointer data) +{ + int ret = WIFI_DIRECT_ERROR_NONE; + wifi_direct_state_e direct_state = WIFI_DIRECT_STATE_DEACTIVATED; + + g_print("====== Start p2p connection ======\n"); + + ret = wifi_direct_initialize(); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_initialize failed : %d\n", ret); + return FALSE; + } + + struct ug_data *ugd = (struct ug_data *)data; + + /* Activation / Deactivation state Callback */ + ret = wifi_direct_set_device_state_changed_cb(_activation_cb, (void *)ugd); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_set_device_state_changed_cb failed : %d\n", ret); + goto error; + } + + /* Discovery state Callback */ + ret = wifi_direct_set_discovery_state_changed_cb(_discover_cb, (void *)ugd); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_set_discovery_state_changed_cb failed : %d\n", ret); + goto error; + } + + /* Connection state Callback */ + ret = wifi_direct_set_connection_state_changed_cb(_connection_cb, (void *)ugd); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_set_connection_state_changed_cb failed : %d\n", ret); + goto error; + } + + /* IP address assigning state callback */ + ret = wifi_direct_set_client_ip_address_assigned_cb(_ip_assigned_cb, (void *)ugd); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_set_client_ip_address_assigned_cb failed : %d\n", ret); + goto error; + } + + ret = wifi_direct_get_state(&direct_state); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_get_state failed : %d\n", ret); + goto error; + } + + if (direct_state < WIFI_DIRECT_STATE_ACTIVATED) { + g_print("wifi direct status < WIFI_DIRECT_STATE_ACTIVATED\n"); + g_print("\n------Starting to activate scmirroring------\n"); + ret = wifi_direct_activate(); + if (ret < WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_activate failed : %d\n", ret); + return FALSE; + } + } else { + g_print("wifi direct status >= WIFI_DIRECT_STATE_ACTIVATED.. Disconnect all first\n"); + ret = wifi_direct_disconnect_all(); + if (!ret) + g_print("wifi_direct_disconnect_all success\n"); + else + g_print("wifi_direct_disconnect_all fail\n"); + + ret = __start_wifi_display_connection(); + if (ret == TRUE) { + g_print("__start_wifi_display_connection success\n"); + } else { + g_print("__start_wifi_display_connection fail\n"); + goto error; + } + } + + return TRUE; + +error: + ret = wifi_direct_deinitialize(); + + return FALSE; +} + +static gboolean __disconnect_p2p_connection(void) +{ + int ret = WIFI_DIRECT_ERROR_NONE; + + ret = wifi_direct_deactivate(); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_deactivate failed : %d\n", ret); + return FALSE; + } + + ret = wifi_direct_deinitialize(); + if (ret != WIFI_DIRECT_ERROR_NONE) { + g_print("Error : wifi_direct_deinitialize failed : %d\n", ret); + return FALSE; + } + + g_print("------p2p connection disconnected------\n"); + + return TRUE; +} +#endif + +#ifndef TEST_WITH_WIFI_DIRECT +static int __scmirroring_secondary_sink_create(gpointer data) +{ + int ret = SCMIRRORING_ERROR_NONE; + + ret = scmirroring_secondary_sink_create(&g_scmirroring); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_create fail [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + //char ip[50]={0}; + //strncpy(ip,"192.168.0.23",50); + //g_print("IP is %s\n", ip); + //ret=scmirroring_sink_set_coupled_ip(g_scmirroring,ip); + if (g_sinktype != -1) { + if (g_sinktype == SCMIRRORING_DISPLAY_TYPE_OVERLAY) { + evas_object_show(g_evas); + ret = scmirroring_secondary_sink_set_display(g_scmirroring, SCMIRRORING_DISPLAY_TYPE_OVERLAY, (void *)g_evas); + } else if (g_sinktype == SCMIRRORING_DISPLAY_TYPE_EVAS) { + g_eo = create_evas_image_object(g_evas); + evas_object_image_size_set(g_eo, 800, 1200); + evas_object_image_fill_set(g_eo, 0, 0, 800, 1200); + evas_object_resize(g_eo, 800, 1200); + evas_object_show(g_evas); + ret = scmirroring_secondary_sink_set_display(g_scmirroring, SCMIRRORING_DISPLAY_TYPE_EVAS, (void *)g_eo); + } + + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_set_display fail [%d]", ret); + return FALSE; + } + } + + ret = scmirroring_secondary_sink_prepare(g_scmirroring); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_prepare fail [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + return ret; +} +#endif + +gboolean __scmirroring_secondary_sink_start(gpointer data) +{ + int ret = SCMIRRORING_ERROR_NONE; + g_print("__scmirroring_secondary_sink_start \n"); + +#ifdef TEST_WITH_WIFI_DIRECT + ret = scmirroring_secondary_sink_create(&g_scmirroring); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_create fail [%d]", ret); + return FALSE; + } + + if (g_resolution != 0) { + ret = scmirroring_secondary_sink_set_resolution(g_scmirroring, g_resolution); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Failed to set resolution, error[%d]\n", ret); + } + + if (g_sinktype != -1) { + + if (g_sinktype == SCMIRRORING_DISPLAY_TYPE_OVERLAY) { + evas_object_show(g_evas); + ret = scmirroring_secondary_sink_set_display(g_scmirroring, SCMIRRORING_DISPLAY_TYPE_OVERLAY, (void *)g_evas); + } else if (g_sinktype == SCMIRRORING_DISPLAY_TYPE_EVAS) { + g_eo = create_evas_image_object(g_evas); + evas_object_image_size_set(g_eo, 800, 1200); + evas_object_image_fill_set(g_eo, 0, 0, 800, 1200); + evas_object_resize(g_eo, 800, 1200); + evas_object_show(g_evas); + ret = scmirroring_secondary_sink_set_display(g_scmirroring, SCMIRRORING_DISPLAY_TYPE_EVAS, (void *)g_eo); + } + + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_set_display fail [%d]", ret); + return FALSE; + } + } + + ret = scmirroring_secondary_sink_prepare(g_scmirroring); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_prepare fail [%d]", ret); + return FALSE; + } + + ret = scmirroring_secondary_sink_set_ip_and_port(g_scmirroring, g_peer_ip, g_peer_port); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_set_ip_and_port fail [%d]", ret); + return FALSE; + } + + g_print("Input server IP and port number IP[%s] Port[%s]\n", g_peer_ip, g_peer_port); +#endif + + ret = scmirroring_secondary_sink_set_state_changed_cb(g_scmirroring, scmirroring_sink_state_callback, NULL); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_set_state_changed_cb fail [%d]", ret); + return FALSE; + } + + ret = scmirroring_secondary_sink_connect(g_scmirroring); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_secondary_sink_connect fail [%d]", ret); + return FALSE; + } + + g_print("__scmirroring_secondary_sink_start \n"); + return FALSE; +} + +gboolean _scmirroring_start_jobs(gpointer data) +{ +#ifdef TEST_WITH_WIFI_DIRECT + int ret = WIFI_DIRECT_ERROR_NONE; + + ret = __start_p2p_connection(data); + if (ret == FALSE) + return FALSE; +#endif + + return TRUE; +} + +int main(int argc, char *argv[]) +{ + int ret = 0; + GIOChannel *stdin_channel; + + stdin_channel = g_io_channel_unix_new(0); + g_io_channel_set_flags(stdin_channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc)__input, NULL); + + __displaymenu(); + + ops.data = NULL; + ret = appcore_efl_main(PACKAGE, &argc, &argv, &ops); + + return ret; +}