From: Hyunsoo Park Date: Fri, 3 May 2019 05:35:21 +0000 (+0900) Subject: Merge branch 'tizen_dev' into tizen X-Git-Tag: submit/tizen/20190507.101459^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f67b44171a742a8168c6a1336f005962136d5a33;p=platform%2Fcore%2Fapi%2Fscreen-mirroring.git Merge branch 'tizen_dev' into tizen Change-Id: Idcf4419f12244350503822e9e471a4f44364d346 --- f67b44171a742a8168c6a1336f005962136d5a33 diff --cc include/scmirroring_internal.h index ece8e68,8af1812..2b8f42d --- a/include/scmirroring_internal.h +++ b/include/scmirroring_internal.h @@@ -19,6 -19,6 +19,7 @@@ #include #include ++#include #ifdef __cplusplus extern "C" { diff --cc include/scmirroring_primary_sink.h index 0000000,529c1e2..e013e69 mode 000000,100644..100644 --- a/include/scmirroring_primary_sink.h +++ b/include/scmirroring_primary_sink.h @@@ -1,0 -1,985 +1,1074 @@@ + /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved ++* Copyright (c) 2019 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_PRIMARY_SINK_H__ + #define __TIZEN_MEDIA_SCMIRRORING_PRIMARY_SINK_H__ + + #include + #include ++#include + + #ifdef __cplusplus + extern "C" { + #endif /* __cplusplus */ + + /** + * @file scmirroring_primary_sink.h - * @brief This file contains the screen mirroring source API and functions related with screen mirroring as primary sink device. ++ * @brief This file contains APIs and functions related with screen mirroring as primary sink device. + */ + + /** + * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE + * @{ + */ + + /** + * @brief Creates a new screen mirroring primary sink handle. + * @since_tizen 5.5 + * + * @remarks You must release @a scmirroring_primary_sink using scmirroring_primary_sink_destroy(). + * + * @param[out] scmirroring_primary_sink A newly returned handle to the screen mirroring primary 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_primary_sink_destroy() + */ + int scmirroring_primary_sink_create(scmirroring_primary_sink_h *scmirroring_primary_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 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * + * @see scmirroring_primary_sink_create() + */ + int scmirroring_primary_sink_set_state_changed_cb(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_sink_state_cb callback, void *user_data); + + /** + * @brief Sets server IP and port. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * + * @see scmirroring_primary_sink_create() + */ + int scmirroring_primary_sink_set_ip_and_port(scmirroring_primary_sink_h scmirroring_primary_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 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * + * @see scmirroring_primary_sink_create() + */ + int scmirroring_primary_sink_set_display(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_display_type_e type, void *display_surface); + + /** + * @brief Sets resolutions of screen mirroring primary sink. + * @details This function sets resolutions of screen mirroring primary 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 primary sink will be disconnected. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary sink + * @param[in] resolution Resolution of screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * + * @see scmirroring_primary_sink_create() + */ + int scmirroring_primary_sink_set_resolution(scmirroring_primary_sink_h scmirroring_primary_sink, int resolution); + + /** + * @brief Prepares the screen mirroring primary sink handle and allocates specific resources. + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_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_primary_sink_create() + * @see scmirroring_primary_sink_set_state_changed_cb() + */ + int scmirroring_primary_sink_prepare(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Creates connection and prepare for receiving data from SCMIRRORING source. + * + * @since_tizen 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_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_primary_sink_create() + * @see scmirroring_primary_sink_set_state_changed_cb() + * @see scmirroring_primary_sink_prepare() + */ + int scmirroring_primary_sink_connect(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Starts receiving data from the SCMIRRORING source and display it(mirror). + * + * @since_tizen 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_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_primary_sink_create() + * @see scmirroring_primary_sink_set_state_changed_cb() + * @see scmirroring_primary_sink_prepare() + * @see scmirroring_primary_sink_connect() + */ + int scmirroring_primary_sink_start(scmirroring_primary_sink_h scmirroring_primary_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 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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_primary_sink_create() + * @see scmirroring_primary_sink_set_state_changed_cb() + * @see scmirroring_primary_sink_prepare() + * @see scmirroring_primary_sink_connect() + * @see scmirroring_primary_sink_start() + */ + int scmirroring_primary_sink_pause(scmirroring_primary_sink_h scmirroring_primary_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 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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_primary_sink_pause() + */ + int scmirroring_primary_sink_resume(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Disconnects and stops receiving data from the SCMIRRORING source. + * + * @since_tizen 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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_primary_sink_create() + * @see scmirroring_primary_sink_set_state_changed_cb() + * @see scmirroring_primary_sink_prepare() + * @see scmirroring_primary_sink_connect() + * @see scmirroring_primary_sink_start() + */ + int scmirroring_primary_sink_disconnect(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Unprepares screen mirroring. + * @details This function unprepares screen mirroring, which closes specific resources. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @post The screen mirroring state will be #SCMIRRORING_SINK_STATE_NULL + * + * @see scmirroring_primary_sink_create() + * @see scmirroring_primary_sink_set_state_changed_cb() + * @see scmirroring_primary_sink_prepare() + */ + int scmirroring_primary_sink_unprepare(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Unregisters the callback function user registered. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * + * @see scmirroring_primary_sink_create() + * @see scmirroring_primary_sink_set_state_changed_cb() + */ + int scmirroring_primary_sink_unset_state_changed_cb(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Destroys screen mirroring primary sink handle. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre The screen mirroring state should be #SCMIRRORING_SINK_STATE_NULL + * + * @see scmirroring_primary_sink_create() + */ + int scmirroring_primary_sink_destroy(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Gets negotiated video codec of screen mirroring primary sink. + * @details The video codec is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ -int scmirroring_primary_sink_get_negotiated_video_codec(scmirroring_primary_sink_h *scmirroring_primary_sink, scmirroring_video_codec_e *codec); ++int scmirroring_primary_sink_get_negotiated_video_codec(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_video_codec_e *codec); + + /** + * @brief Gets negotiated video resolution of screen mirroring primary sink. + * @details The video resolution is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ -int scmirroring_primary_sink_get_negotiated_video_resolution(scmirroring_primary_sink_h *scmirroring_primary_sink, int *width, int *height); ++int scmirroring_primary_sink_get_negotiated_video_resolution(scmirroring_primary_sink_h scmirroring_primary_sink, int *width, int *height); + + /** + * @brief Gets negotiated frame rate of screen mirroring primary sink. + * @details The video frame rate is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ -int scmirroring_primary_sink_get_negotiated_video_frame_rate(scmirroring_primary_sink_h *scmirroring_primary_sink, int *frame_rate); ++int scmirroring_primary_sink_get_negotiated_video_frame_rate(scmirroring_primary_sink_h scmirroring_primary_sink, int *frame_rate); + + /** + * @brief Gets negotiated audio codec of screen mirroring primary sink. + * @details The audio codec is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ -int scmirroring_primary_sink_get_negotiated_audio_codec(scmirroring_primary_sink_h *scmirroring_primary_sink, scmirroring_audio_codec_e *codec); ++int scmirroring_primary_sink_get_negotiated_audio_codec(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_audio_codec_e *codec); + + /** + * @brief Gets negotiated audio channel of screen mirroring primary sink. + * @details The audio channel is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ -int scmirroring_primary_sink_get_negotiated_audio_channel(scmirroring_primary_sink_h *scmirroring_primary_sink, int *channel); ++int scmirroring_primary_sink_get_negotiated_audio_channel(scmirroring_primary_sink_h scmirroring_primary_sink, int *channel); + + /** + * @brief Gets negotiated audio sample rate of screen mirroring primary sink. + * @details The audio sample rate is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ -int scmirroring_primary_sink_get_negotiated_audio_sample_rate(scmirroring_primary_sink_h *scmirroring_primary_sink, int *sample_rate); ++int scmirroring_primary_sink_get_negotiated_audio_sample_rate(scmirroring_primary_sink_h scmirroring_primary_sink, int *sample_rate); + + /** + * @brief Gets negotiated audio bitwidth of screen mirroring primary sink. + * @details The audio bitwidth is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + * @pre Register user callback by calling scmirroring_primary_sink_set_state_changed_cb(). + * @pre Call scmirroring_primary_sink_prepare() + * @pre Call scmirroring_primary_sink_connect() + * @pre The screen mirroring state must be #SCMIRRORING_SINK_STATE_CONNECTED or #SCMIRRORING_SINK_STATE_PLAYING + */ -int scmirroring_primary_sink_get_negotiated_audio_bitwidth(scmirroring_primary_sink_h *scmirroring_primary_sink, int *bitwidth); ++int scmirroring_primary_sink_get_negotiated_audio_bitwidth(scmirroring_primary_sink_h scmirroring_primary_sink, int *bitwidth); + + /** + * @brief Gets the current state of screen mirroring primary sink. + * @details The current state of screen mirroring primary sink izzs changed by calling CAPIs. And it provides the state of screen mirroring primary sink the time this api is called. + * - * @since_tizen 5.0 ++ * @since_tizen 5.5 + * + * @param[in] scmirroring_primary_sink The handle to the screen mirroring primary sink + * @param[out] state The current state of screen mirroring primary 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 primary sink handle by calling scmirroring_primary_sink_create(). + */ + int scmirroring_primary_sink_get_current_state(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_sink_state_e *state); -int scmirroring_primary_sink_set_coupled_sink_status(scmirroring_primary_sink_h scmirroring_primary_sink, int status); + ++/** ++ * @brief Called when user wants to set 'address' of screen mirroring primary sink. ++ * ++ * @details It sets MAC address to screen mirroring primary sink's property. ++ * ++ * @since_tizen 5.5 ++ * ++ * @param[in] scmirroring_primary_sink Screen mirroring primary sink handle ++ * @param[in] address Mac address of coupled screen mirroring coupled sink. ++ * ++ * @pre scmirroring_primary_sink_create() ++ * ++ * @see scmirroring_primary_sink_create() ++ */ ++int scmirroring_primary_sink_set_coupled_sink(scmirroring_primary_sink_h scmirroring_primary_sink, gchar* address); ++ ++/** ++ * @brief Called when user wants to set 'status' of screen mirroring primary sink. ++ * ++ * @details It sets status to screen mirroring primary sink's property. ++ * ++ * @since_tizen 5.5 ++ * ++ * @param[in] scmirroring_primary_sink Screen mirroring primary sink handle ++ * @param[in] address Mac address of coupled screen mirroring coupled sink. ++ * ++ * @pre scmirroring_primary_sink_create() ++ * ++ * @see scmirroring_primary_sink_create() ++ */ ++int scmirroring_primary_sink_set_coupled_sink_status(scmirroring_primary_sink_h scmirroring_primary_sink, int status); + + /** + * @brief Creates screen mirroring source handle. + * @remarks You must release @a scmirroring_primary_sink using scmirroring_primary_src_destroy(). + * ++ * @since_tizen 5.5 ++ * + * @param[out] scmirroring_primary_sink The handle to screen mirroring source + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @see scmirroring_primary_src_destroy() + */ + int scmirroring_primary_src_create(scmirroring_primary_sink_h *scmirroring_primary_sink); + + /** + * @brief Registers user callback to get status of screen mirroring. + * @details This function registers user callback and this callback is called when each status is changed. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * + * @see scmirroring_primary_src_create() + */ + int scmirroring_primary_src_set_state_changed_cb(scmirroring_primary_sink_h scmirroring_primary_sink_src, scmirroring_state_cb callback, void *user_data); + + /** + * @brief Sets connection mode of screen mirroring. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @param[in] connection_mode connection mode of screen mirroring + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * + * @see scmirroring_primary_src_create() + */ + int scmirroring_primary_src_set_connection_mode(scmirroring_primary_sink_h scmirroring_primary_sink_src, scmirroring_connection_mode_e connection_mode); + + /** + * @brief Sets IP address and port number of screen mirroring source. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @param[in] ip Server IP address + * @param[in] port Server port + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * + * @see scmirroring_primary_src_create() + */ + int scmirroring_primary_src_set_ip_and_port(scmirroring_primary_sink_h scmirroring_primary_sink_src, const char *ip, const char *port); + + /** + * @brief Sets resolution of screen mirroring source. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @param[in] resolution Resolution of screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * + * @see scmirroring_primary_src_create() + */ + int scmirroring_primary_src_set_resolution(scmirroring_primary_sink_h scmirroring_primary_sink_src, scmirroring_resolution_e resolution); + + /** + * @brief Sets name of screen mirroring source server. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @param[in] name Name of screen mirroring source server + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * + * @see scmirroring_primary_src_create() + */ + int scmirroring_primary_src_set_server_name(scmirroring_primary_sink_h scmirroring_primary_sink_src, const char *name); + + /** + * @brief Enables/Disables screen mirroring multisink. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @param[in] multisink Ability to send to multisink + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * + * @see scmirroring_primary_src_create() + */ + int scmirroring_primary_src_set_multisink_ability(scmirroring_primary_sink_h scmirroring_primary_sink_src, scmirroring_multisink_e multisink); + + /** + * @brief Connects to server for screen mirroring as source, asynchronously. + * @details This function launches server and connects to the server for screen mirroring as source to command server to start/pause/resume/stop. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_CONNECTION_TIME_OUT Connection timeout + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * @pre Register user callback by calling scmirroring_primary_src_set_state_changed_cb(). + * @post The screen mirroring state will be SCMIRRORING_STATE_READY + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + */ + int scmirroring_primary_src_connect(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Starts screen mirroring, asynchronously. + * @details This function starts screen mirroring, which means it starts to negotiate and stream RTP multimedia data. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_CONNECTION_TIME_OUT Connection timeout + * @retval #SCMIRRORING_ERROR_NOT_SUPPORTED Not supported + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * @pre Register user callback by calling scmirroring_primary_src_set_state_changed_cb(). + * @pre Call scmirroring_primary_src_connect() + * @post The screen mirroring state will be SCMIRRORING_STATE_CONNECTION_WAIT if server starts to listen + * @post The screen mirroring state will be SCMIRRORING_STATE_CONNECTED if client connects to the server + * @post The screen mirroring state will be SCMIRRORING_STATE_PLAYING if server starts to stream multimedia data + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + * @see scmirroring_primary_src_connect() + */ + int scmirroring_primary_src_start(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Pauses screen mirroring, asynchronously. + * @details This function pauses screen mirroring, which means it sends RTSP PAUSE trigger message to sink. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre The screen mirroring state should be SCMIRRORING_STATE_PLAYING + * @post The screen mirroring state will be SCMIRRORING_STATE_PAUSED + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + * @see scmirroring_primary_src_connect() + * @see scmirroring_primary_src_start() + */ + int scmirroring_primary_src_pause(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Resumes screen mirroring, asynchronously. + * @details This function resumes screen mirroring, which means it sends RTSP PLAY message to sink. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre The screen mirroring state should be SCMIRRORING_STATE_PAUSED + * @post The screen mirroring state will be SCMIRRORING_STATE_PLAYING + * + * @see scmirroring_primary_src_pause() + */ + int scmirroring_primary_src_resume(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Enable streaming without reencoding for screen mirroring. + * @details This function enable streaming without reencoding for screen mirroring, which means files that encoded with supported formats will be streamed without decoding and reencoding. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @param[in] enable Ability to stream file directly + * @param[in] uri_srcname File name to stream directly + * + * @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 Not enough memory to allocate new object + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION External function not implemented + * + * @pre The screen mirroring state should be SCMIRRORING_STATE_PLAYING + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + * @see scmirroring_primary_src_connect() + * @see scmirroring_primary_src_start() + */ + int scmirroring_primary_src_set_direct_streaming(scmirroring_primary_sink_h scmirroring_primary_sink_src, scmirroring_direct_streaming_e enable, const char *uri_srcname); ++ ++/** ++ * @brief Make Miracast Server 'coupling' mode. ++ * @details This function make Miracast Server 'coupling' mode. ++ * If it is set, connected sink devices is considered as secondary sink and both are goint to try coupling. ++ * ++ * @since_tizen 5.5 ++ * ++ * @param[in] scmirroring_primary_sink The handle to screen mirroring source ++ * @param[in] coupling_mode value which set coupling mode (0 : disable, 1 : enable) ++ * ++ * @return @c 0 on success, ++ * otherwise a negative error value ++ * ++ * @retval #SCMIRRORING_ERROR_NONE Successful ++ * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter ++ * ++ * @pre The screen mirroring state should be SCMIRRORING_STATE_PLAYING ++ * ++ * @see scmirroring_primary_src_create() ++ * @see scmirroring_primary_src_set_state_changed_cb() ++ * @see scmirroring_primary_src_connect() ++ * @see scmirroring_primary_src_start() ++ */ + int scmirroring_primary_src_set_coupling_mode(scmirroring_primary_sink_h scmirroring, scmirroring_coupling_mode_e coupling_mode); + + /** + * @brief Change transport for AV streaming. + * @details This function changes transport for AV streaming. Default transport is UDP. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * @param[in] transport Transport for audio/video streaming data + * + * @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 Not enough memory to allocate new object + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION External function not implemented + * + * @pre The screen mirroring state should be SCMIRRORING_STATE_PLAYING + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + * @see scmirroring_primary_src_connect() + * @see scmirroring_primary_src_start() + */ + int scmirroring_primary_src_AV_transport_switch(scmirroring_primary_sink_h scmirroring_primary_sink_src, scmirroring_av_transport_e transport); + + /** + * @brief Stops screen mirroring, asynchronously. + * @details This function stops screen mirroring, which means it sends RTSP TEARDOWN trigger message to sink. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_CONNECTION_TIME_OUT Connection timeout + * + * @pre The screen mirroring state should be SCMIRRORING_STATE_PAUSED or SCMIRRORING_STATE_PLAYING + * @post The screen mirroring state will be SCMIRRORING_STATE_TEARDOWN + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + * @see scmirroring_primary_src_connect() + * @see scmirroring_primary_src_start() + */ + int scmirroring_primary_src_stop(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Disconnects server for screen mirroring. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_CONNECTION_TIME_OUT Connection timeout + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * @pre Register user callback by calling scmirroring_primary_src_set_state_changed_cb(). + * @pre Connects to server for screen mirroring source by calling scmirroring_primary_src_connect(). + * @post The screen mirroring state will be SCMIRRORING_STATE_NULL + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + * @see scmirroring_primary_src_connect() + */ + int scmirroring_primary_src_disconnect(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Unregisters the callback function user registered + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * @pre Register user callback by calling scmirroring_primary_src_set_state_changed_cb(). + * + * @see scmirroring_primary_src_create() + * @see scmirroring_primary_src_set_state_changed_cb() + */ + int scmirroring_primary_src_unset_state_changed_cb(scmirroring_primary_sink_h scmirroring_primary_sink); + + /** + * @brief Destroys server and screen mirroring source handle. + * ++ * @since_tizen 5.5 ++ * + * @param[in] scmirroring_primary_sink The handle to screen mirroring source + * + * @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 Not enough memory is available + * @retval #SCMIRRORING_ERROR_INVALID_OPERATION Invalid operation + * @retval #SCMIRRORING_ERROR_CONNECTION_TIME_OUT Connection timeout + * + * @pre Create a screen mirroring source handle by calling scmirroring_primary_src_create(). + * @pre The screen mirroring state should be SCMIRRORING_STATE_NULL + * + * @see scmirroring_primary_src_create() + */ + int scmirroring_primary_src_destroy(scmirroring_primary_sink_h scmirroring_primary_sink); + + #ifdef __cplusplus + } + #endif /* __cplusplus */ + + /** + * @} + */ + + #endif /* __TIZEN_MEDIA_SCMIRRORING_PRIMARY_SINK_H__ */ diff --cc include/scmirroring_private.h index f3dee22,93d6239..e74e3f1 --- a/include/scmirroring_private.h +++ b/include/scmirroring_private.h @@@ -144,6 -145,41 +145,41 @@@ typedef struct unsigned int magic_num; } scmirroring_sink_s; + typedef struct { + unsigned int magic_num; + MMHandleType mm_handle; + char *ip; + char *port; + bool use_hdcp; + char *server_name; + int resolution; + int connected; + int sock; + int source_id; + GIOChannel *channel; + char *sock_path; + int connect_mode; + int current_state; + scmirroring_state_cb_s *scmirroring_state_cb; + scmirroring_sink_state_cb_s *scmirroring_sink_state_cb; + scmirroring_multisink_e multisink; + scmirroring_direct_streaming_e direct_streaming; + char *filesrc; + scmirroring_av_transport_e av_transport; + char *coupled_sink_address; + scmirroring_coupling_mode_e coupling_mode; //MAKE SERVER COUPLING MODE + } scmirroring_primary_sink_s; + + + typedef struct { ++ unsigned int magic_num; + MMHandleType mm_handle; + char *ip; + char *port; + bool use_hdcp; + scmirroring_sink_state_cb_s *scmirroring_sink_state_cb; - unsigned int magic_num; + } scmirroring_secondary_sink_s; + #define WIFIDIRECT_DISPLAY_FEATURE "http://tizen.org/feature/network.wifi.direct.display" #define CHECK_FEATURE_SUPPORTED(feature_name)\ diff --cc include/scmirroring_secondary_sink.h index 0000000,f087750..35b4e17 mode 000000,100755..100755 --- a/include/scmirroring_secondary_sink.h +++ b/include/scmirroring_secondary_sink.h @@@ -1,0 -1,477 +1,493 @@@ + /* -* Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved ++* Copyright (c) 2019 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 ++#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. ++ * @brief This file contains APIs and functions related with screen mirroring as secondary sink device. ++ + */ + + /** + * @addtogroup CAPI_MEDIA_SCREEN_MIRRORING_MODULE + * @{ + */ + + /** + * @brief Creates a new screen mirroring secondary sink handle. + * @since_tizen 5.5 + * + * @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 secondary 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 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 Prepares the screen mirroring sink handle and allocates specific resources. + * @since_tizen 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 secondary sink handle. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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 audio codec of screen mirroring secondary sink. + * @details The audio codec is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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); ++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 secondary sink. + * @details The audio channel is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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); ++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 secondary sink. + * @details The audio sample rate is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @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); ++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 secondary sink. + * @details The audio bitwidth is negotiated by screen mirroring source. + * + * @since_tizen 5.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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); ++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 secondary 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.5 + * + * @param[in] scmirroring_secondary_sink The handle to the screen mirroring secondary 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); + ++/** ++ * @brief Called when user wants to set 'address' of screen mirroring sink. ++ * ++ * @details It sets MAC address to screen mirroring sink's property. ++ * ++ * @param[in] scmirroring_secondary_sink Screen mirroring secondary sink handle ++ * @param[in] address Mac address of coupled screen mirroring sink. ++ * ++ * @pre scmirroring_secondary_sink_create() ++ * ++ * @see scmirroring_secondary_sink_create() ++ */ ++int scmirroring_secondary_sink_set_coupled_sink(scmirroring_secondary_sink_h scmirroring_secondary_sink, gchar* address); ++ + #ifdef __cplusplus + } + #endif /* __cplusplus */ + + /** + * @} + */ + + #endif /*__TIZEN_MEDIA_SCMIRRORING_SECONDARY_SINK_H__*/ diff --cc include/scmirroring_src.h index fa1dc04,1f15a4d..d0e24c3 --- a/include/scmirroring_src.h +++ b/include/scmirroring_src.h @@@ -166,7 -166,8 +166,32 @@@ int scmirroring_src_set_server_name(scm * @see scmirroring_src_create() */ int scmirroring_src_set_multisink_ability(scmirroring_src_h scmirroring_src, scmirroring_multisink_e multisink); + ++/** ++ * @brief Make Miracast Server 'coupling' mode. ++ * @details This function make Miracast Server 'coupling' mode. ++ * If it is set, connected sink devices is considered as secondary sink and both are goint to try coupling. ++ * ++ * @since_tizen 5.5 ++ * ++ * @param[in] scmirroring The handle to screen mirroring source ++ * @param[in] coupling_mode value which set coupling mode (0 : disable, 1 : enable) ++ * ++ * @return @c 0 on success, ++ * otherwise a negative error value ++ * ++ * @retval #SCMIRRORING_ERROR_NONE Successful ++ * @retval #SCMIRRORING_ERROR_INVALID_PARAMETER Invalid parameter ++ * ++ * @pre The screen mirroring state should be SCMIRRORING_STATE_PLAYING ++ * ++ * @see scmirroring_primary_src_create() ++ * @see scmirroring_primary_src_set_state_changed_cb() ++ * @see scmirroring_primary_src_connect() ++ * @see scmirroring_primary_src_start() ++ */ + int scmirroring_src_set_coupling_mode(scmirroring_src_h scmirroring, scmirroring_coupling_mode_e coupling_mode); + /** * @brief Connects to server for screen mirroring as source, asynchronously. * @details This function launches server and connects to the server for screen mirroring as source to command server to start/pause/resume/stop. diff --cc include/scmirroring_type_internal.h index 0000000,0000000..89ed15f new file mode 100644 --- /dev/null +++ b/include/scmirroring_type_internal.h @@@ -1,0 -1,0 +1,67 @@@ ++/* ++* Copyright (c) 2019 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_TYPE_INTERNAL_H__ ++#define __TIZEN_MEDIA_SCMIRRORING_TYPE_INTERNAL_H__ ++ ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++/** ++ * @file scmirroring_type_internal.h ++ * @brief This file contains API related to screen mirroring enumerations for classes of errors. ++ */ ++ ++/** ++ * @brief The handle to the screen mirroring primary sink. ++ * @since_tizen 5.5 ++ */ ++typedef void *scmirroring_primary_sink_h; ++ ++/** ++ * @brief The handle to the screen mirroring secondary sink. ++ * @since_tizen 5.5 ++ */ ++typedef void *scmirroring_secondary_sink_h; ++ ++/** ++ * @brief Enumeration for screen mirroring coupling mode. ++ * @since_tizen 5.5 ++ */ ++typedef enum { ++ SCMIRRORING_COUPLING_MODE_DISABLED = 0, /**< Disable coupling mode of miracast server */ ++ SCMIRRORING_COUPLING_MODE_ENABLED /**< Enable coupling mode of miracast server */ ++} scmirroring_coupling_mode_e; ++ ++/** ++ * @brief Enumeration for screen mirroring coupling status. ++ * @since_tizen 5.5 ++ */ ++typedef enum { ++ SCMIRRORING_COUPLING_STATUS_NOT_COUPLED = 0, ++ SCMIRRORING_COUPLING_STATUS_COUPLED, ++ SCMIRRORING_COUPLING_STATUS_TEARDOWN_COUPLING, ++ SCMIRRORING_COUPLING_STATUS_MAX ++} scmirroring_coupled_sink_status_e; ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* __TIZEN_MEDIA_SCMIRRORING_TYPE_INTERNAL_H__ */ diff --cc miracast_server/miracast_server.h index 4a7b4f6,b91c4c9..7b7d7e7 --- a/miracast_server/miracast_server.h +++ b/miracast_server/miracast_server.h @@@ -50,6 -50,7 +50,7 @@@ struct _MiracastServer gint resolution; gint connection_mode; gint multisink; - gint coupling_mode; ++ gint coupling_mode; gpointer _gst_reserved[GST_PADDING]; }; diff --cc miracast_server/miracast_server_impl.c index 64b243c,82a0a2e..95efc13 --- a/miracast_server/miracast_server_impl.c +++ b/miracast_server/miracast_server_impl.c @@@ -492,6 -497,14 +497,14 @@@ __client_closed(GstRTSPClient *client, scmirroring_debug("client %p: connection closed", client); - /* Sends Secondary sink ip to scmirroring_src */ - if(g_strcmp0(gst_rtsp_connection_get_ip(connection), COUPLED_SINK_ADDRESS) == 0){ ++ /* Sends coupled sink address to scmirroring_src */ ++ if(server_obj->coupling_mode == 1){ + gchar * msg = g_malloc(sizeof(char *) * 50); + g_sprintf(msg, "MESSAGE:COUPLED_SINK_ADDRESS:%s", gst_rtsp_connection_get_ip(connection)); + klass->send_response(server_obj,msg); + g_free(msg); + usleep(250000); + } klass->send_response(server_obj, "OK:STOP"); return; diff --cc packaging/capi-media-screen-mirroring.spec index 2345f6c,d9cd16d..b0399f7 --- a/packaging/capi-media-screen-mirroring.spec +++ b/packaging/capi-media-screen-mirroring.spec @@@ -1,6 -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.97 ++Version: 0.2.0 Release: 0 Group: Multimedia/API License: Apache-2.0 @@@ -94,7 -94,9 +94,10 @@@ cp -rf %{_builddir}/%{name}-%{version}/ %files devel %{_includedir}/media/scmirroring_src.h %{_includedir}/media/scmirroring_sink.h + %{_includedir}/media/scmirroring_primary_sink.h + %{_includedir}/media/scmirroring_secondary_sink.h %{_includedir}/media/scmirroring_type.h ++%{_includedir}/media/scmirroring_type_internal.h %{_includedir}/media/scmirroring_src_ini.h %{_includedir}/media/scmirroring_internal.h %{_includedir}/media/miracast_server.h diff --cc src/scmirroring_primary_sink.c index 0000000,eaa4beb..dd05936 mode 000000,100644..100644 --- a/src/scmirroring_primary_sink.c +++ b/src/scmirroring_primary_sink.c @@@ -1,0 -1,1826 +1,1801 @@@ + /* -* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved ++* Copyright (c) 2019 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 + #include + + #define MAX_MSG_LEN 128 + #define TIMEOUT_SEC 2 + #define CONNECTED_TO_SERVER 1 + #define NOT_CONNECTED_TO_SERVER 0 + + static scmirroring_error_e __scmirroring_primary_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_primary_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_primary_sink_set_message_cb(int error_type, MMWFDSinkStateType state_type, void *uData) + { + scmirroring_error_e error = __scmirroring_primary_sink_error_convert(__func__, error_type); + scmirroring_sink_state_e state = __scmirroring_primary_sink_state_convert(state_type); + scmirroring_primary_sink_s *handle = (scmirroring_primary_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_primary_sink_create(scmirroring_primary_sink_h *scmirroring_primary_sink) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)calloc(1, sizeof(scmirroring_primary_sink_s)); + + scmirroring_error("New to Create"); + + handle->magic_num = SCMIRRORING_MAGIC_NUMBER; + + handle->mm_handle = 0; + handle->use_hdcp = TRUE; + handle->scmirroring_sink_state_cb = NULL; + + handle->ip = NULL; + handle->port = NULL; + handle->filesrc = NULL; + handle->connected = NOT_CONNECTED_TO_SERVER; + handle->use_hdcp = TRUE; + handle->resolution = 0; + handle->connect_mode = SCMIRRORING_CONNECTION_WIFI_DIRECT; + handle->scmirroring_state_cb = NULL; + handle->sock = -1; + handle->channel = NULL; + handle->sock_path = NULL; + handle->current_state = SCMIRRORING_STATE_CREATED; + handle->server_name = g_strdup("scmirroring"); + handle->multisink = SCMIRRORING_MULTISINK_DISABLE; + handle->av_transport = SCMIRRORING_AV_TRANSPORT_UDP; + handle->coupling_mode = SCMIRRORING_COUPLING_MODE_DISABLED; + + ret = mm_wfd_sink_create_r2(&handle->mm_handle); + if (ret != MM_ERROR_NONE) { + SCMIRRORING_SAFE_FREE(handle); + scmirroring_error("Fail to Create"); + return __scmirroring_primary_sink_error_convert(__func__, ret); + } + + *scmirroring_primary_sink = (scmirroring_primary_sink_h)handle; + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_set_ip_and_port(scmirroring_primary_sink_h scmirroring_primary_sink, const char *ip, const char *port) + { + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_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_primary_sink_prepare(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + + ret = mm_wfd_sink_prepare(handle->mm_handle); + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_connect(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + char server_uri[255] = {0, }; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_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_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_unprepare(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + + ret = mm_wfd_sink_unprepare(handle->mm_handle); + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_destroy(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_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_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_start(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + + ret = mm_wfd_sink_start(handle->mm_handle); + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_disconnect(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + + ret = mm_wfd_sink_disconnect(handle->mm_handle); + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_set_state_changed_cb(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_sink_state_cb callback, void *user_data) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_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_primary_sink_set_message_cb, handle); + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_unset_state_changed_cb(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_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_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_set_display(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_display_type_e type, void *display_surface) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_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_primary_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_primary_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_primary_sink_error_convert(__func__, ret); + } + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_set_resolution(scmirroring_primary_sink_h scmirroring_primary_sink, int resolution) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_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_primary_sink_error_convert(__func__, ret); + } + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_pause(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + + ret = mm_wfd_sink_pause(handle->mm_handle); + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_resume(scmirroring_primary_sink_h scmirroring_primary_sink) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + + ret = mm_wfd_sink_resume(handle->mm_handle); + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + -int scmirroring_primary_sink_get_negotiated_video_codec(scmirroring_primary_sink_h *scmirroring_primary_sink, scmirroring_video_codec_e *codec) ++int scmirroring_primary_sink_get_negotiated_video_codec(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_video_codec_e *codec) + { + int ret = SCMIRRORING_ERROR_NONE; + int mm_codec = MM_WFD_SINK_VIDEO_CODEC_NONE; + - scmirroring_primary_sink_s *handle = NULL; ++ scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + scmirroring_debug_fenter(); + - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); - scmirroring_retvm_if(codec == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "codec is NULL"); - - handle = (scmirroring_primary_sink_s *)(*scmirroring_primary_sink); - scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); ++ scmirroring_retvm_if(codec == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "codec is NULL"); + + *codec = SCMIRRORING_VIDEO_CODEC_NONE; + + ret = mm_wfd_sink_get_negotiated_video_codec(handle->mm_handle, &mm_codec); + ret = __scmirroring_primary_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_primary_sink_get_negotiated_video_resolution(scmirroring_primary_sink_h *scmirroring_primary_sink, int *width, int *height) ++int scmirroring_primary_sink_get_negotiated_video_resolution(scmirroring_primary_sink_h scmirroring_primary_sink, int *width, int *height) + { + int ret = SCMIRRORING_ERROR_NONE; + - scmirroring_primary_sink_s *handle = NULL; ++ scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + scmirroring_debug_fenter(); + - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); ++ scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + 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_primary_sink_s *)(*scmirroring_primary_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_primary_sink is invalid handle"); - + *width = 0; + *height = 0; + + ret = mm_wfd_sink_get_negotiated_video_resolution(handle->mm_handle, width, height); + ret = __scmirroring_primary_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_primary_sink_get_negotiated_video_frame_rate(scmirroring_primary_sink_h *scmirroring_primary_sink, int *frame_rate) ++int scmirroring_primary_sink_get_negotiated_video_frame_rate(scmirroring_primary_sink_h scmirroring_primary_sink, int *frame_rate) + { + int ret = SCMIRRORING_ERROR_NONE; + - scmirroring_primary_sink_s *handle = NULL; ++ scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + scmirroring_debug_fenter(); + - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); - scmirroring_retvm_if(frame_rate == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "frame_rate is NULL"); - - handle = (scmirroring_primary_sink_s *)(*scmirroring_primary_sink); - scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); ++ scmirroring_retvm_if(frame_rate == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "frame_rate is NULL"); + + *frame_rate = 0; + + ret = mm_wfd_sink_get_negotiated_video_frame_rate(handle->mm_handle, frame_rate); + ret = __scmirroring_primary_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_primary_sink_get_negotiated_audio_codec(scmirroring_primary_sink_h *scmirroring_primary_sink, scmirroring_audio_codec_e *codec) ++int scmirroring_primary_sink_get_negotiated_audio_codec(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_audio_codec_e *codec) + { + int ret = SCMIRRORING_ERROR_NONE; + int mm_codec = MM_WFD_SINK_AUDIO_CODEC_NONE; + - scmirroring_primary_sink_s *handle = NULL; ++ scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + scmirroring_debug_fenter(); + - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); - scmirroring_retvm_if(codec == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "codec is NULL"); - - handle = (scmirroring_primary_sink_s *)(*scmirroring_primary_sink); - scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); ++ scmirroring_retvm_if(codec == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "codec is NULL"); + + *codec = SCMIRRORING_AUDIO_CODEC_NONE; + + ret = mm_wfd_sink_get_negotiated_audio_codec(handle->mm_handle, &mm_codec); + ret = __scmirroring_primary_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_primary_sink_get_negotiated_audio_channel(scmirroring_primary_sink_h *scmirroring_primary_sink, int *channel) ++int scmirroring_primary_sink_get_negotiated_audio_channel(scmirroring_primary_sink_h scmirroring_primary_sink, int *channel) + { + int ret = SCMIRRORING_ERROR_NONE; + - scmirroring_primary_sink_s *handle = NULL; ++ scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + scmirroring_debug_fenter(); + - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); - scmirroring_retvm_if(channel == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "channel is NULL"); - - handle = (scmirroring_primary_sink_s *)(*scmirroring_primary_sink); - scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); ++ scmirroring_retvm_if(channel == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "channel is NULL"); + + *channel = 0; + + ret = mm_wfd_sink_get_negotiated_audio_channel(handle->mm_handle, channel); + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + scmirroring_debug("channel: %d", *channel); + scmirroring_debug_fleave(); + + return ret; + } + -int scmirroring_primary_sink_get_negotiated_audio_sample_rate(scmirroring_primary_sink_h *scmirroring_primary_sink, int *sample_rate) ++int scmirroring_primary_sink_get_negotiated_audio_sample_rate(scmirroring_primary_sink_h scmirroring_primary_sink, int *sample_rate) + { + int ret = SCMIRRORING_ERROR_NONE; + - scmirroring_primary_sink_s *handle = NULL; ++ scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + scmirroring_debug_fenter(); + - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); - scmirroring_retvm_if(sample_rate == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "sample_rate is NULL"); - - handle = (scmirroring_primary_sink_s *)(*scmirroring_primary_sink); - scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); ++ scmirroring_retvm_if(sample_rate == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "sample_rate is NULL"); + + *sample_rate = 0; + + ret = mm_wfd_sink_get_negotiated_audio_sample_rate(handle->mm_handle, sample_rate); + ret = __scmirroring_primary_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_primary_sink_get_negotiated_audio_bitwidth(scmirroring_primary_sink_h *scmirroring_primary_sink, int *bitwidth) ++int scmirroring_primary_sink_get_negotiated_audio_bitwidth(scmirroring_primary_sink_h scmirroring_primary_sink, int *bitwidth) + { + int ret = SCMIRRORING_ERROR_NONE; + - scmirroring_primary_sink_s *handle = NULL; ++ scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + scmirroring_debug_fenter(); + - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); - scmirroring_retvm_if(bitwidth == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "bitwidth is NULL"); - - handle = (scmirroring_primary_sink_s *)(*scmirroring_primary_sink); - scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "handle is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); ++ scmirroring_retvm_if(bitwidth == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "bitwidth is NULL"); + + *bitwidth = 0; + + ret = mm_wfd_sink_get_negotiated_audio_bitwidth(handle->mm_handle, bitwidth); + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + if (ret != SCMIRRORING_ERROR_NONE) + return ret; + + scmirroring_debug("bitwidth: %d", *bitwidth); + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_get_current_state(scmirroring_primary_sink_h scmirroring_primary_sink, scmirroring_sink_state_e *state) + { + int result = MM_ERROR_NONE; + int mm_state = MM_WFD_SINK_STATE_NONE; + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)(scmirroring_primary_sink); + + scmirroring_debug_fenter(); - scmirroring_retvm_if(scmirroring_primary_sink == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink* is NULL"); - scmirroring_retvm_if(state == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "state is NULL"); ++ scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); ++ scmirroring_retvm_if(state == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "state is NULL"); ++ + + result = mm_wfd_sink_get_current_state(handle->mm_handle, &mm_state); + if (result == MM_ERROR_NONE) { + *state = __scmirroring_primary_sink_state_convert(mm_state); + scmirroring_debug("ScreenMirroring current state is [%d]", *state); + } + scmirroring_debug_fleave(); + return __scmirroring_primary_sink_error_convert(__func__, result); + } + + int scmirroring_primary_sink_set_coupled_sink(scmirroring_primary_sink_h scmirroring_primary_sink, gchar* address) + { + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_debug_fenter(); + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + scmirroring_retvm_if(address == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "MAC address is invalid"); + + scmirroring_debug("address [%s]", address); + + ret = mm_wfd_sink_set_coupled_sink(handle->mm_handle, address); + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set Coupled IP"); + return __scmirroring_primary_sink_error_convert(__func__, ret); + } + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_sink_set_coupled_sink_status(scmirroring_primary_sink_h scmirroring_primary_sink, int status) + { + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *handle = (scmirroring_primary_sink_s *)scmirroring_primary_sink; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(handle == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is NULL"); + scmirroring_retvm_if(handle->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring_primary_sink is invalid handle"); + + if ((status < SCMIRRORING_COUPLING_STATUS_NOT_COUPLED) || (status >= SCMIRRORING_COUPLING_STATUS_MAX)) { + scmirroring_error("Invalid status : %d", status); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + scmirroring_debug("coupled sink status(%d)", status); + ret = mm_wfd_sink_set_coupled_sink_status(handle->mm_handle, status); + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set resolution"); + return __scmirroring_primary_sink_error_convert(__func__, ret); + } + + ret = __scmirroring_primary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } + + static gboolean __scmirroring_primary_src_callback_call(gpointer data) + { + scmirroring_primary_sink_s *scmirroring = (scmirroring_primary_sink_s *) data; + + if (scmirroring == NULL) { + scmirroring_error("SCMIRRORING is NULL"); + return FALSE; + } + + scmirroring_state_cb_s *cb_info = scmirroring->scmirroring_state_cb; + + if ((cb_info != NULL) && (cb_info->state_cb != NULL)) { + scmirroring_debug("Calling user callback(error: %d, status: %d)", cb_info->error_code, cb_info->src_state); + cb_info->state_cb(cb_info->error_code, cb_info->src_state, cb_info->user_data); + } + + if (cb_info != NULL && cb_info->src_state == SCMIRRORING_STATE_NULL) { + SCMIRRORING_SAFE_FREE(scmirroring->ip); + SCMIRRORING_SAFE_FREE(scmirroring->port); + SCMIRRORING_SAFE_FREE(scmirroring->scmirroring_state_cb); + + g_io_channel_shutdown(scmirroring->channel, FALSE, NULL); + g_io_channel_unref(scmirroring->channel); + + SCMIRRORING_SAFE_G_FREE(scmirroring->sock_path); + SCMIRRORING_SAFE_FREE(scmirroring); + } + + return FALSE; + } + + static int __scmirroring_primary_src_send_cmd_to_server(scmirroring_primary_sink_s *scmirroring, const char *cmd) + { + int ret = SCMIRRORING_ERROR_NONE; + char *_cmd = NULL; + int _cmdLen = 0; + + scmirroring_retvm_if(scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "scmirroring is NULL"); + scmirroring_retvm_if(cmd == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "cmd is NULL"); + + _cmd = g_strdup(cmd); + if (_cmd == NULL) { + scmirroring_error("Out of memory for command buffer"); + return SCMIRRORING_ERROR_OUT_OF_MEMORY; + } + + _cmdLen = strlen(_cmd) + 1; + if (write(scmirroring->sock, _cmd, _cmdLen) != _cmdLen) { + char buf[255] = {0, }; + strerror_r(errno, buf, sizeof(buf)); + scmirroring_error("sendto failed [%s]", buf); + ret = SCMIRRORING_ERROR_INVALID_OPERATION; + } else { + scmirroring_debug("Sent message [%s] successfully", _cmd); + } + + SCMIRRORING_SAFE_G_FREE(_cmd); + + return ret; + } + + static int __miracast_server_launch(scmirroring_primary_sink_s *scmirroring) + { + int ret = SCMIRRORING_ERROR_NONE; + GDBusProxy *proxy = NULL; + GVariant *reg = NULL; + GDBusConnection *conn = NULL; + GError *error = NULL; + + #if !GLIB_CHECK_VERSION(2, 35, 0) + g_type_init(); + #endif + + scmirroring_debug("-----------socket connect failed it means server is not yet started------------"); + scmirroring_debug("going to start miracast server"); + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (error) { + scmirroring_error("Failed to get dbus connection: %s", error->message); + g_error_free(error); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + gchar *name = NULL; + gchar *if_name = NULL; + gchar *obj_path = NULL; + + if (scmirroring->server_name) { + name = g_strdup_printf("org.tizen.%s.server", scmirroring->server_name); + if_name = g_strdup_printf("org.tizen.%s.server", scmirroring->server_name); + obj_path = g_strdup_printf("/org/tizen/%s/server", scmirroring->server_name); + } else { + name = g_strdup("org.tizen.scmirroring.server"); + if_name = g_strdup("org.tizen.scmirroring.server"); + obj_path = g_strdup("/org/tizen/scmirroring/server"); + } + + scmirroring_debug("Server Name : %s", name); + + proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + name, + obj_path, + if_name, + NULL, + &error); + g_free(name); + g_free(if_name); + g_free(obj_path); + g_object_unref(conn); + if (proxy == NULL) { + scmirroring_error("g_dbus_proxy_new_sync failed : %s", error->message); + g_error_free(error); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + reg = g_dbus_proxy_call_sync(proxy, "launch_method", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); + g_object_unref(proxy); + + if (reg) { + g_variant_unref(reg); + reg = NULL; + } + if (error) { + scmirroring_error("g_dbus_proxy_call_sync failed : %s", error->message); + g_error_free(error); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + scmirroring_debug("Miracast server is launched successfully"); + + return ret; + } + + /* + * Application - miracast server message + * 1. Response Message from miracast server + * [Error:Status] + * - OK:LISTENING + * - OK:CONNECTED + * - OK:STOP + * - OK:DESTROY + * + * 2. Request Message from application to miracast server + * - START [ip addr:port] + * - SET [sth] + */ + + static int __scmirroring_primary_src_get_error(gchar *str) + { + if (g_strrstr(str, "OK")) + return SCMIRRORING_ERROR_NONE; + else if (g_strrstr(str, "FAIL")) + return SCMIRRORING_ERROR_INVALID_OPERATION; + + return SCMIRRORING_ERROR_NONE; + } + + static int __scmirroring_primary_src_get_status(gchar *str) + { + if (g_strrstr(str, "LISTENING")) + return SCMIRRORING_STATE_CONNECTION_WAIT; + else if (g_strrstr(str, "CONNECTED")) + return SCMIRRORING_STATE_CONNECTED; + else if (g_strrstr(str, "PLAYING")) + return SCMIRRORING_STATE_PLAYING; + else if (g_strrstr(str, "SET")) + return SCMIRRORING_STATE_READY; + else if (g_strrstr(str, SCMIRRORING_STATE_CMD_PAUSE)) + return SCMIRRORING_STATE_PAUSED; + else if (g_strrstr(str, SCMIRRORING_STATE_CMD_RESUME)) + return SCMIRRORING_STATE_PLAYING; + else if (g_strrstr(str, SCMIRRORING_STATE_CMD_STOP)) + return SCMIRRORING_STATE_TEARDOWN; + else if (g_strrstr(str, SCMIRRORING_STATE_CMD_DESTROY)) + return SCMIRRORING_STATE_NULL; + + return SCMIRRORING_STATE_CREATED; + } + + static int __scmirroring_primary_src_get_messages(scmirroring_primary_sink_s *scmirroring, gchar *key, gchar* value) + { + if (g_strrstr(key, "COUPLED_SINK_ADDRESS")) { + //if this is set, coupled_sink_status would be 0b01. + scmirroring->coupled_sink_address = g_strdup(value); + + return SCMIRRORING_STATE_CONNECTED; + } + return SCMIRRORING_STATE_CREATED; + } + + static void __scmirroring_primary_src_set_callback_info(scmirroring_primary_sink_s *scmirroring, int error_code, int state) + { + scmirroring_state_cb_s *cb_info = scmirroring->scmirroring_state_cb; + if (cb_info) { + cb_info->error_code = error_code; + cb_info->src_state = state; + + GSource *src_user_cb = NULL; + src_user_cb = g_idle_source_new(); + g_source_set_callback(src_user_cb, (GSourceFunc)__scmirroring_primary_src_callback_call, scmirroring, NULL); + g_source_attach(src_user_cb, g_main_context_get_thread_default()); + } else { + scmirroring_error("There is no callback"); + } + + return; + } + + static void __scmirroring_primary_src_interpret(scmirroring_primary_sink_s *scmirroring, char *buf) + { + scmirroring_debug("Received : %s", buf); + + int error_code = SCMIRRORING_ERROR_INVALID_OPERATION; + int src_state = SCMIRRORING_STATE_CREATED; + gchar **response; + response = g_strsplit(buf, ":", 0); + + scmirroring_debug("error: %s, status: %s", response[0], response[1]); + + /* state messages */ + if(g_strcmp0("OK",response[0]) == 0 || g_strcmp0("FAIL",response[0]) == 0){ + error_code = __scmirroring_primary_src_get_error(response[0]); + src_state = __scmirroring_primary_src_get_status(response[1]); + + if (scmirroring->current_state != src_state) { + scmirroring->current_state = src_state; + __scmirroring_primary_src_set_callback_info(scmirroring, error_code, src_state); + } else { + scmirroring_debug("Current state is already %d", src_state); + } + /* other messages, state is depended on response[1] and actual messages are response[2] */ + } else if (g_strcmp0("MESSAGE", response[0]) == 0 ) { + error_code = __scmirroring_primary_src_get_error(response[0]); + src_state = __scmirroring_primary_src_get_messages(scmirroring, response[1], response[2]); - scmirroring_debug("message key : %s , value : %s", response[1], response[2]); ++ scmirroring_debug("MESSAGE key : %s , value : %s", response[1], response[2]); + __scmirroring_primary_src_set_callback_info(scmirroring, error_code, src_state); + + if (!g_strcmp0("COUPLED_SINK_ADDRESS", response[1])) { - g_print("yes , coupled_sink_address"); ++ scmirroring_primary_sink_set_coupled_sink(scmirroring, response[2]); + scmirroring_primary_sink_set_coupled_sink_status(scmirroring, 1); + } + } + g_strfreev(response); + + return; + } + + gboolean __scmirroring_primary_src_read_cb(GIOChannel *src, GIOCondition condition, gpointer data) + { + char buf[MAX_MSG_LEN + 1]; + gsize read; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)data; + + if (condition & G_IO_IN) { + g_io_channel_read_chars(_scmirroring->channel, buf, MAX_MSG_LEN, &read, NULL); + if (read == 0) { + scmirroring_error("Read 0 bytes"); + return FALSE; + } else { + scmirroring_debug("Read %" G_GSIZE_FORMAT " bytes", read); + } + + gsize i = 0; + gsize idx = 0; + + /* Handling multiple response like "CMD1\0CMD2\0CMD3\0" */ + for (i = 0; i < read; i++) { + gchar *str = NULL; + if (buf[i] == '\0') { + str = buf + idx; + idx = i + 1; + } else { + continue; + } + scmirroring_debug("Handling %s", str); + __scmirroring_primary_src_interpret(_scmirroring, str); + if (idx >= read) break; + } + } else if (condition & G_IO_ERR) { + scmirroring_error("got G_IO_ERR"); + return FALSE; + } else if (condition & G_IO_HUP) { + scmirroring_error("got G_IO_HUP"); + return FALSE; + } + + return TRUE; + } + + static int __scmirroring_primary_src_send_set_cm(scmirroring_primary_sink_h scmirroring) + { + /* Set connection mode to miracast server */ + char *cmd = NULL; + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + cmd = g_strdup_printf("SET CM %d", _scmirroring->connect_mode); + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, cmd); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_G_FREE(cmd); + scmirroring_error("Failed to be ready [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + SCMIRRORING_SAFE_G_FREE(cmd); + + return ret; + } + + static int __scmirroring_primary_src_send_set_ip(scmirroring_primary_sink_h scmirroring) + { + /* Set IP and Port to server */ + char *cmd = NULL; + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + cmd = g_strdup_printf("SET IP %s:%s", _scmirroring->ip, _scmirroring->port); + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, cmd); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_G_FREE(cmd); + scmirroring_error("Failed to be ready [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + SCMIRRORING_SAFE_G_FREE(cmd); + + return ret; + } + + static int __scmirroring_primary_src_send_set_reso(scmirroring_primary_sink_h scmirroring) + { + /* Set resolution to miracast server */ + char *cmd = NULL; + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + cmd = g_strdup_printf("SET RESO %d", _scmirroring->resolution); + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, cmd); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_G_FREE(cmd); + scmirroring_error("Failed to be ready [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + SCMIRRORING_SAFE_G_FREE(cmd); + + return ret; + } + + static int __scmirroring_primary_src_send_set_multisink(scmirroring_primary_sink_h scmirroring) + { + /* Set resolution to miracast server */ + char *cmd = NULL; + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + cmd = g_strdup_printf("SET MULTISINK %d", _scmirroring->multisink); + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, cmd); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_G_FREE(cmd); + scmirroring_error("Failed to be ready [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + SCMIRRORING_SAFE_G_FREE(cmd); + + return ret; + } + + static int __scmirroring_primary_src_send_set_direct_streaming(scmirroring_primary_sink_h scmirroring) + { + /* Set resolution to miracast server */ + char *cmd = NULL; + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + cmd = g_strdup_printf("SET STREAMING %d %s", _scmirroring->direct_streaming, _scmirroring->filesrc); + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, cmd); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_FREE(cmd); + scmirroring_error("Failed to enable direct streaming [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + SCMIRRORING_SAFE_FREE(cmd); + + return ret; + } + + static int __scmirroring_primary_src_send_set_coupling_mode(scmirroring_primary_sink_h scmirroring) + { + /* Set coupling mode to miracast server */ + char *cmd = NULL; + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + cmd = g_strdup_printf("SET COUPLING_MODE %d", _scmirroring->coupling_mode); + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, cmd); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_G_FREE(cmd); + scmirroring_error("Failed to be ready [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + SCMIRRORING_SAFE_G_FREE(cmd); + + return ret; + } + + static int __scmirroring_primary_src_send_switch_transport(scmirroring_primary_sink_h scmirroring) + { + /* Set tranport protocol to miracast server */ + char *cmd = NULL; + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + const char *tr = _scmirroring->av_transport == SCMIRRORING_AV_TRANSPORT_UDP ? "UDP" : "TCP"; + + cmd = g_strdup_printf("SWITCH %s", tr); + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, cmd); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_G_FREE(cmd); + scmirroring_error("Failed to be ready [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + SCMIRRORING_SAFE_G_FREE(cmd); + + return ret; + } + + int scmirroring_primary_src_create(scmirroring_primary_sink_h *scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = NULL; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + _scmirroring = (scmirroring_primary_sink_s *)calloc(1, sizeof(scmirroring_primary_sink_s)); + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY"); + + _scmirroring->magic_num = SCMIRRORING_MAGIC_NUMBER; + _scmirroring->ip = NULL; + _scmirroring->port = NULL; + _scmirroring->filesrc = NULL; + _scmirroring->connected = NOT_CONNECTED_TO_SERVER; + _scmirroring->use_hdcp = TRUE; + _scmirroring->resolution = 0; + _scmirroring->connect_mode = SCMIRRORING_CONNECTION_WIFI_DIRECT; + _scmirroring->scmirroring_state_cb = NULL; + _scmirroring->sock = -1; + _scmirroring->channel = NULL; + _scmirroring->sock_path = NULL; + _scmirroring->current_state = SCMIRRORING_STATE_CREATED; + _scmirroring->server_name = g_strdup("scmirroring"); + _scmirroring->multisink = SCMIRRORING_MULTISINK_DISABLE; + _scmirroring->av_transport = SCMIRRORING_AV_TRANSPORT_UDP; + _scmirroring->coupling_mode = SCMIRRORING_COUPLING_MODE_DISABLED; + + *scmirroring = (scmirroring_primary_sink_h)_scmirroring; + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_set_connection_mode(scmirroring_primary_sink_h scmirroring, scmirroring_connection_mode_e connect_mode) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if ((connect_mode < SCMIRRORING_CONNECTION_WIFI_DIRECT) || (connect_mode >= SCMIRRORING_CONNECTION_MAX)) { + scmirroring_error("INVALID Connection mode : %d", connect_mode); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + _scmirroring->connect_mode = connect_mode; + + if (_scmirroring->connected) + ret = __scmirroring_primary_src_send_set_cm(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_set_state_changed_cb(scmirroring_primary_sink_h scmirroring, scmirroring_state_cb callback, void *user_data) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + scmirroring_retvm_if(callback == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "callback is NULL"); + + if (_scmirroring->scmirroring_state_cb == NULL) { + _scmirroring->scmirroring_state_cb = (scmirroring_state_cb_s *)calloc(1, sizeof(scmirroring_state_cb_s)); + scmirroring_retvm_if(_scmirroring->scmirroring_state_cb == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Error Set CB"); + } else { + memset(_scmirroring->scmirroring_state_cb, 0, sizeof(scmirroring_state_cb_s)); + } + + _scmirroring->scmirroring_state_cb->user_data = user_data; + _scmirroring->scmirroring_state_cb->state_cb = callback; + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_unset_state_changed_cb(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if (_scmirroring->scmirroring_state_cb != NULL) { + _scmirroring->scmirroring_state_cb->user_data = NULL; + _scmirroring->scmirroring_state_cb->state_cb = NULL; + } + + SCMIRRORING_SAFE_FREE(_scmirroring->scmirroring_state_cb); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_set_ip_and_port(scmirroring_primary_sink_h scmirroring, const char *ip, const char *port) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + scmirroring_retvm_if(!STRING_VALID(ip), SCMIRRORING_ERROR_INVALID_PARAMETER, "INVALID IP"); + scmirroring_retvm_if(!STRING_VALID(port), SCMIRRORING_ERROR_INVALID_PARAMETER, "INVALID PORT"); + + SCMIRRORING_SAFE_FREE(_scmirroring->ip); + _scmirroring->ip = strdup(ip); + scmirroring_retvm_if(_scmirroring->ip == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Out of memory for IP"); + + SCMIRRORING_SAFE_FREE(_scmirroring->port); + _scmirroring->port = strdup(port); + scmirroring_retvm_if(_scmirroring->port == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Out of memory for PORT"); + + if (_scmirroring->connected) + ret = __scmirroring_primary_src_send_set_ip(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_set_resolution(scmirroring_primary_sink_h scmirroring, scmirroring_resolution_e resolution) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if ((resolution < SCMIRRORING_RESOLUTION_1920x1080_P30) || (resolution >= SCMIRRORING_RESOLUTION_MAX)) { + scmirroring_error("INVALID resolution : %d", resolution); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + _scmirroring->resolution = resolution; + + if (_scmirroring->connected) + ret = __scmirroring_primary_src_send_set_reso(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_set_server_name(scmirroring_primary_sink_h scmirroring, const char *name) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + SCMIRRORING_SAFE_G_FREE(_scmirroring->server_name); + _scmirroring->server_name = g_strdup(name); + scmirroring_retvm_if(_scmirroring->server_name == NULL, SCMIRRORING_ERROR_OUT_OF_MEMORY, "Out of memory for server name"); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_set_multisink_ability(scmirroring_primary_sink_h scmirroring, scmirroring_multisink_e multisink) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if ((multisink < SCMIRRORING_MULTISINK_DISABLE) || (multisink > SCMIRRORING_MULTISINK_ENABLE)) { + scmirroring_error("INVALID multisink ability : %d", multisink); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + _scmirroring->multisink = multisink; + + if (_scmirroring->connected) + ret = __scmirroring_primary_src_send_set_multisink(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_connect(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + int retry = 0; + struct sockaddr_un serv_addr; + int sock = -1; + GIOChannel *channel = NULL; + struct timeval tv_timeout = { TIMEOUT_SEC, 0 }; + char buf[255] = {0, }; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + scmirroring_retvm_if(_scmirroring->connected == CONNECTED_TO_SERVER, SCMIRRORING_ERROR_NONE, "already connected to server."); + + /*Create TCP Socket*/ + if ((sock = socket(PF_FILE, SOCK_STREAM, 0)) < 0) { + strerror_r(errno, buf, sizeof(buf)); + scmirroring_error("socket failed: %s", buf); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv_timeout, sizeof(tv_timeout)) == -1) { + strerror_r(errno, buf, sizeof(buf)); + scmirroring_error("setsockopt failed: %s", buf); + close(sock); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + channel = g_io_channel_unix_new(sock); + if (channel == NULL) { + strerror_r(errno, buf, sizeof(buf)); + scmirroring_error("g_io_channel_unix_new failed: %s", buf); + } + + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL); + + _scmirroring->sock = sock; + _scmirroring->channel = channel; + SCMIRRORING_SAFE_G_FREE(_scmirroring->sock_path); + _scmirroring->sock_path = g_strdup("/tmp/.miracast_ipc_rtspserver"); + + /* Connecting to the miracast server */ + memset(&serv_addr, 0, sizeof(struct sockaddr_un)); + serv_addr.sun_family = AF_UNIX; + strncpy(serv_addr.sun_path, _scmirroring->sock_path, sizeof(serv_addr.sun_path)); + serv_addr.sun_path[sizeof(serv_addr.sun_path) - 1] = '\0'; + + try: + scmirroring_debug("Trying to connect to the miracast server"); + if (connect(_scmirroring->sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + /* Once failed to connect, try to launch miracast server */ + if (retry == 0) { + ret = __miracast_server_launch(_scmirroring); + if (ret != SCMIRRORING_ERROR_NONE) { + SCMIRRORING_SAFE_G_FREE(_scmirroring->sock_path); + scmirroring_error("__miracast_server_launch error : %d", ret); + return ret; + } + retry++; + goto try; + } else { + scmirroring_debug("Trying to connect failed"); + if (retry < 5) { + scmirroring_debug("Trying to connect again.."); + retry++; + usleep(10000); + goto try; + } + + strerror_r(errno, buf, sizeof(buf)); + scmirroring_error("Connect error : %s", buf); + close(_scmirroring->sock); + _scmirroring->sock = -1; + SCMIRRORING_SAFE_G_FREE(_scmirroring->sock_path); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + } else { + scmirroring_debug("Connected successfully"); + } + + /* Create new channel to watch tcp socket */ + GSource *source = NULL; + source = g_io_create_watch(_scmirroring->channel, G_IO_IN | G_IO_HUP | G_IO_ERR); + int source_id = -1; + + /* Set callback to be called when socket is readable */ + g_source_set_callback(source, (GSourceFunc)__scmirroring_primary_src_read_cb, _scmirroring, NULL); + source_id = g_source_attach(source, g_main_context_get_thread_default()); + + _scmirroring->source_id = source_id; + _scmirroring->connected = CONNECTED_TO_SERVER; + _scmirroring->current_state = SCMIRRORING_STATE_READY; + + __scmirroring_primary_src_set_callback_info(_scmirroring, SCMIRRORING_ERROR_NONE, SCMIRRORING_STATE_READY); + + if ((_scmirroring->ip != NULL) || (_scmirroring->port != NULL)) { + ret = __scmirroring_primary_src_send_set_ip(_scmirroring); + ret = __scmirroring_primary_src_send_set_cm(_scmirroring); + ret = __scmirroring_primary_src_send_set_reso(_scmirroring); + } + + if (_scmirroring->multisink == SCMIRRORING_MULTISINK_ENABLE) + ret = __scmirroring_primary_src_send_set_multisink(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_disconnect(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + scmirroring_retvm_if(_scmirroring->connected == NOT_CONNECTED_TO_SERVER, SCMIRRORING_ERROR_NONE, "Already disconnected"); + + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, SCMIRRORING_STATE_CMD_DESTROY); + if (ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("Failed to destroy miracast server [%d]", ret); + + if (_scmirroring->channel != NULL) { + g_io_channel_shutdown(_scmirroring->channel, FALSE, NULL); + g_io_channel_unref(_scmirroring->channel); + _scmirroring->channel = NULL; + } + + if (_scmirroring->sock != -1) { + close(_scmirroring->sock); + _scmirroring->sock = -1; + } + + SCMIRRORING_SAFE_G_FREE(_scmirroring->sock_path); + _scmirroring->connected = NOT_CONNECTED_TO_SERVER; + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_start(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, SCMIRRORING_STATE_CMD_START); + if (ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("Failed to start [%d]", ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_pause(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, SCMIRRORING_STATE_CMD_PAUSE); + if (ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("Failed to pause [%d]", ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_resume(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, SCMIRRORING_STATE_CMD_RESUME); + if (ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("Failed to resume [%d]", ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_set_direct_streaming(scmirroring_primary_sink_h scmirroring_primary_src, + scmirroring_direct_streaming_e enable, const char* uri_srcname) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + int len = 0; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring_primary_src; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + scmirroring_retvm_if(!STRING_VALID(uri_srcname), SCMIRRORING_ERROR_INVALID_PARAMETER, "INVALID URI_SRCNAME"); + _scmirroring->direct_streaming = enable; + + len = strlen(uri_srcname); + if (_scmirroring->filesrc != NULL) { + g_free(_scmirroring->filesrc); + _scmirroring->filesrc = NULL; + } + _scmirroring->filesrc = g_strndup(uri_srcname, len); + + if ((_scmirroring->filesrc == NULL)) { + scmirroring_error("OUT_OF_MEMORY"); + return SCMIRRORING_ERROR_OUT_OF_MEMORY; + } + + ret = __scmirroring_primary_src_send_set_direct_streaming(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + + int scmirroring_primary_src_set_coupling_mode(scmirroring_primary_sink_h scmirroring, scmirroring_coupling_mode_e coupling_mode) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); - scmirroring_error("scmirroring_primary_src_set_coupling_mode1"); + + if ((coupling_mode < SCMIRRORING_COUPLING_MODE_DISABLED) || (coupling_mode > SCMIRRORING_COUPLING_MODE_ENABLED)) { + scmirroring_error("INVALID coupling mode : %d", coupling_mode); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } - scmirroring_error("scmirroring_primary_src_set_coupling_mode2"); - + - _scmirroring->coupling_mode = coupling_mode; - scmirroring_error("scmirroring_primary_src_set_coupling_mode3"); ++ _scmirroring->coupling_mode = coupling_mode; + + if (_scmirroring->connected) - ret = __scmirroring_primary_src_send_set_coupling_mode(_scmirroring); - scmirroring_error("scmirroring_primary_src_set_coupling_mode4"); ++ ret = __scmirroring_primary_src_send_set_coupling_mode(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_AV_transport_switch(scmirroring_primary_sink_h scmirroring, + scmirroring_av_transport_e transport) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if (transport < SCMIRRORING_AV_TRANSPORT_UDP || transport > SCMIRRORING_AV_TRANSPORT_TCP) { + scmirroring_error("Invalid transport"); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } + + _scmirroring->av_transport = transport; + + ret = __scmirroring_primary_src_send_switch_transport(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_stop(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + ret = __scmirroring_primary_src_send_cmd_to_server(_scmirroring, SCMIRRORING_STATE_CMD_STOP); + if (ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("Failed to be stop [%d]", ret); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_primary_src_destroy(scmirroring_primary_sink_h scmirroring) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + scmirroring_primary_sink_s *_scmirroring = (scmirroring_primary_sink_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if (_scmirroring->connected == CONNECTED_TO_SERVER) { + ret = scmirroring_primary_src_disconnect(scmirroring); + if (ret != SCMIRRORING_ERROR_NONE) + scmirroring_error("Failed to disconnect server [%d]", ret); + } + + SCMIRRORING_SAFE_FREE(_scmirroring->scmirroring_state_cb); + SCMIRRORING_SAFE_G_FREE(_scmirroring->server_name); + + scmirroring_debug_fleave(); + + return ret; + } + diff --cc src/scmirroring_secondary_sink.c index 0000000,ef309f4..762b5f4 mode 000000,100755..100755 --- a/src/scmirroring_secondary_sink.c +++ b/src/scmirroring_secondary_sink.c @@@ -1,0 -1,578 +1,566 @@@ + /* -* Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved ++* Copyright (c) 2019 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_secondary_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_secondary_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_r2(&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_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_audio_codec(scmirroring_secondary_sink_h *scmirroring_secondary_sink, scmirroring_audio_codec_e *codec) ++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_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(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 == 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(codec == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "codec is NULL"); + + *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 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_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(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 == 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(channel == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "channel is NULL"); + + *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 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_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(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 == 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(sample_rate == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "sample_rate is NULL"); + + *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 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_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(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 == 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(bitwidth == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "bitwidth is NULL"); + + *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_secondary_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_sink(scmirroring_secondary_sink_h scmirroring_secondary_sink, gchar* address) + { + 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"); + scmirroring_retvm_if(address, SCMIRRORING_ERROR_INVALID_PARAMETER, "MAC address is invalid"); + + scmirroring_debug("address[%s]", address); + + ret = mm_wfd_sink_set_coupled_sink(handle->mm_handle, address); + + if (ret != MM_ERROR_NONE) { + scmirroring_error("Fail to Set Coupled sink"); + return __scmirroring_secondary_sink_error_convert(__func__, ret); + } + ret = __scmirroring_secondary_sink_error_convert(__func__, ret); + + scmirroring_debug_fleave(); + + return ret; + } diff --cc src/scmirroring_src.c index 474f1ff,ddb0cdf..b375068 --- a/src/scmirroring_src.c +++ b/src/scmirroring_src.c @@@ -240,18 -240,29 +240,29 @@@ static void __scmirroring_src_interpret scmirroring_debug("error: %s, status: %s", response[0], response[1]); - error_code = __scmirroring_src_get_error(response[0]); - src_state = __scmirroring_src_get_status(response[1]);; - g_strfreev(response); - - if (scmirroring->current_state != src_state) { - scmirroring->current_state = src_state; + /* if front-half message is "OK" or "FAIL", it is ERROR:STATE pair*/ + if(g_strcmp0("OK",response[0]) == 0 || g_strcmp0("FAIL",response[0]) == 0){ + error_code = __scmirroring_src_get_error(response[0]); + src_state = __scmirroring_src_get_status(response[1]); + if(response[2] != NULL){ + scmirroring_debug("response2 : %s", response[2]); - } - g_strfreev(response); ++ } + if (scmirroring->current_state != src_state) { + scmirroring->current_state = src_state; + __scmirroring_src_set_callback_info(scmirroring, error_code, src_state); + } else { + scmirroring_debug("Current state is already %d", src_state); + } + } else if (g_strcmp0("SECONDARY_SINK",response[0]) == 0 ) { + /* for coupled sink */ + error_code = SCMIRRORING_ERROR_NONE; + src_state = SCMIRRORING_STATE_TEARDOWN; __scmirroring_src_set_callback_info(scmirroring, error_code, src_state); - } else { - scmirroring_debug("Current state is already %d", src_state); } ++ g_strfreev(response); return; + } gboolean __scmirroring_src_read_cb(GIOChannel *src, GIOCondition condition, gpointer data) @@@ -649,6 -680,35 +680,34 @@@ int scmirroring_src_set_multisink_abili return ret; } + int scmirroring_src_set_coupling_mode(scmirroring_src_h scmirroring, scmirroring_coupling_mode_e coupling_mode) + { + CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); + + int ret = SCMIRRORING_ERROR_NONE; + + scmirroring_src_s *_scmirroring = (scmirroring_src_s *)scmirroring; + + scmirroring_debug_fenter(); + + scmirroring_retvm_if(_scmirroring == NULL, SCMIRRORING_ERROR_INVALID_PARAMETER, "Handle is NULL"); + scmirroring_retvm_if(_scmirroring->magic_num != SCMIRRORING_MAGIC_NUMBER, SCMIRRORING_ERROR_INVALID_PARAMETER, "Invalid handle"); - scmirroring_error("scmirroring_primary_src_set_coupling_mode1"); + + if ((coupling_mode < SCMIRRORING_COUPLING_MODE_DISABLED) || (coupling_mode > SCMIRRORING_COUPLING_MODE_ENABLED)) { + scmirroring_error("INVALID coupling mode : %d", coupling_mode); + return SCMIRRORING_ERROR_INVALID_PARAMETER; + } - _scmirroring->coupling_mode = coupling_mode; ++ _scmirroring->coupling_mode = coupling_mode; + + if (_scmirroring->connected) - ret = __scmirroring_src_send_set_coupling_mode(_scmirroring); ++ ret = __scmirroring_src_send_set_coupling_mode(_scmirroring); + + scmirroring_debug_fleave(); + + return ret; + } + + int scmirroring_src_connect(scmirroring_src_h scmirroring) { CHECK_FEATURE_SUPPORTED(WIFIDIRECT_DISPLAY_FEATURE); diff --cc test_sink/scmirroring_primary_sink_test.c index 0000000,974226f..930626a mode 000000,100644..100644 --- a/test_sink/scmirroring_primary_sink_test.c +++ b/test_sink/scmirroring_primary_sink_test.c @@@ -1,0 -1,1269 +1,1265 @@@ + /* + * 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 + + #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 TEST_PRIMARY_SINK -#define COUPLED_SINK_ADDRESS "192.168.0.50" + #define PACKAGE "screen_mirroring_primary_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_primary_sink_h scmirroring_primary_sink = NULL; + gint g_resolution = 0; + gint g_sinktype = SCMIRRORING_DISPLAY_TYPE_OVERLAY; + + gint g_menu = MAIN_MENU; + GMainLoop *g_loop; + + #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_primary_sink_start(gpointer data); + + #ifndef TEST_WITH_WIFI_DIRECT + static int __scmirroring_primary_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_sink(void); + gboolean __timeout_menu_display(void *data); + + /* for source*/ + int _scmirroring_primary_src_create(void); + /* 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_primary_sink_get_negotiated_video_codec(&scmirroring_primary_sink, &codec); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("Error : scmirroring_primary_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_primary_sink_get_negotiated_video_resolution(&scmirroring_primary_sink, &width, &height); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_primary_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_primary_sink_get_negotiated_video_frame_rate(&scmirroring_primary_sink, &frame_rate); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_primary_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_primary_sink_get_negotiated_audio_codec(&scmirroring_primary_sink, &codec); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("Error : scmirroring_primary_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_primary_sink_get_negotiated_audio_channel(&scmirroring_primary_sink, &channel); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_primary_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_primary_sink_get_negotiated_audio_sample_rate(&scmirroring_primary_sink, &sample_rate); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_primary_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_primary_sink_get_negotiated_audio_bitwidth(&scmirroring_primary_sink, &bitwidth); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Error : scmirroring_primary_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; + } + + //Source user callback + static void scmirroring_source_state_callback(scmirroring_error_e error_code, scmirroring_state_e state, void *user_data) + { + g_print("\n\nReceived Callback error code[%d], state[%d]\n\n", error_code, state); + return; + } + + //Sink user callback + 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_primary_sink_start(scmirroring_primary_sink) != SCMIRRORING_ERROR_NONE) + g_print("scmirroring_primary_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_primary_sink_unprepare(scmirroring_primary_sink) != SCMIRRORING_ERROR_NONE) + g_print("scmirroring_primary_sink_unprepare fail\n"); + if (scmirroring_primary_sink_destroy(scmirroring_primary_sink) != SCMIRRORING_ERROR_NONE) + g_print("scmirroring_primary_sink_destroy fail\n"); + } else + g_print(" state[%d] Invalid State", state); + + return; + } + + static void __quit_program_sink(void) + { + g_print("Quit sink\n"); + + #ifdef TEST_WITH_WIFI_DIRECT + __disconnect_p2p_connection(); + #endif + scmirroring_primary_sink = 0; + elm_exit(); + } + + static void __displaymenu(void) + { + g_print("\n"); + g_print("=====================================================================\n"); + g_print(" SCMIRRORING Primary Sink Testsuite(press q to quit) \n"); + g_print("=====================================================================\n"); + #ifdef TEST_PRIMARY_SINK + g_print("=====================================================================\n"); + g_print(" Source function \n"); + g_print("=====================================================================\n"); + g_print("M : Make mirroring source handle(create handle)\n"); + g_print("A : set ip & port(ex. a 192.168.49.1 2022)\n"); + g_print("O : set coupling_mode(ex. O 1) \n"); + g_print("C : Connect\n"); + g_print("S : Start \n"); + g_print("T : sTop\n"); + g_print("D : Destroy\n"); + g_print("---------------------------------------------------------------------\n"); + #endif + + g_print("=====================================================================\n"); + g_print(" Sink function \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("P : Prepare sink\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("I : Setting Sink\n"); + g_print("K : 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_primary_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"); + + scmirroring_primary_sink = 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_primary_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); + + //Source Side + + if (strncmp(cmd, "M", 1) == 0) { + ret = _scmirroring_primary_src_create(); + } else if (strncmp(cmd, "A", 1) == 0) { + ret = scmirroring_primary_src_set_ip_and_port(scmirroring_primary_sink, 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, "O", 1) == 0) { + ret = scmirroring_primary_src_set_coupling_mode(scmirroring_primary_sink, atoi(value[1])); + g_print("cOupling mode [%d]\n", atoi(value[1])); + } else if (strncmp(cmd, "C", 1) == 0) { + g_print("Set state Changed callback function and Connect\n"); + ret = scmirroring_primary_src_set_state_changed_cb(scmirroring_primary_sink, scmirroring_source_state_callback, NULL); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Failed to set state changed callback\n"); + ret = scmirroring_primary_src_connect(scmirroring_primary_sink); + } else if (strncmp(cmd, "S", 1) == 0) { + g_print("Start\n"); + ret = scmirroring_primary_src_start(scmirroring_primary_sink); + } else if (strncmp(cmd, "T", 1) == 0) { + g_print("Stop\n"); + ret = scmirroring_primary_src_stop(scmirroring_primary_sink); + } else if (strncmp(cmd, "D", 1) == 0) { + g_print("Destroy\n"); + ret = scmirroring_primary_src_destroy(scmirroring_primary_sink); + } + + //Sink side + else if (strncmp(cmd, "P", 1) == 0) { + g_print("prepared \n"); + ret = scmirroring_primary_sink_prepare(scmirroring_primary_sink); + } else if (strncmp(cmd, "d", 1) == 0) { + g_print("Disconnect\n"); + ret = scmirroring_primary_sink_disconnect(scmirroring_primary_sink); + } else if (strncmp(cmd, "p", 1) == 0) { + g_print("Pause\n"); + ret = scmirroring_primary_sink_pause(scmirroring_primary_sink); + } else if (strncmp(cmd, "r", 1) == 0) { + g_print("Resume\n"); + ret = scmirroring_primary_sink_resume(scmirroring_primary_sink); + } else if (strncmp(cmd, "t", 1) == 0) { + g_print("Destroy\n"); + ret = scmirroring_primary_sink_unprepare(scmirroring_primary_sink); + ret = scmirroring_primary_sink_destroy(scmirroring_primary_sink); + } else if (strncmp(cmd, "q", 1) == 0) { + __quit_program_sink(); + } else if (strncmp(cmd, "I", 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, "K", 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_primary_sink_create(NULL); + if (ret == SCMIRRORING_ERROR_NONE) { + ret = scmirroring_primary_sink_set_ip_and_port(scmirroring_primary_sink, 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_primary_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_primary_sink_create(gpointer data) + { + int ret = SCMIRRORING_ERROR_NONE; + + ret = scmirroring_primary_sink_create(&scmirroring_primary_sink); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_sink_create fail [%d]", ret); + return SCMIRRORING_ERROR_INVALID_OPERATION; + } + + if (g_sinktype != -1) { + if (g_sinktype == SCMIRRORING_DISPLAY_TYPE_OVERLAY) { + evas_object_show(g_evas); + ret = scmirroring_primary_sink_set_display(scmirroring_primary_sink, 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_primary_sink_set_display(scmirroring_primary_sink, SCMIRRORING_DISPLAY_TYPE_EVAS, (void *)g_eo); + } + + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_sink_set_display fail [%d]", ret); + return FALSE; + } + } + + return ret; + } + #endif + + gboolean __scmirroring_primary_sink_start(gpointer data) + { + int ret = SCMIRRORING_ERROR_NONE; + g_print("__scmirroring_primary_sink_start \n"); + + #ifdef TEST_WITH_WIFI_DIRECT + ret = scmirroring_primary_sink_create(&scmirroring_primary_sink); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_sink_create fail [%d]", ret); + return FALSE; + } + + if (g_resolution != 0) { + ret = scmirroring_primary_sink_set_resolution(scmirroring_primary_sink, 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_primary_sink_set_display(scmirroring_primary_sink, 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_primary_sink_set_display(scmirroring_primary_sink, SCMIRRORING_DISPLAY_TYPE_EVAS, (void *)g_eo); + } + + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_sink_set_display fail [%d]", ret); + return FALSE; + } + } + + ret = scmirroring_primary_sink_prepare(scmirroring_primary_sink); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_sink_prepare fail [%d]", ret); + return FALSE; + } + + ret = scmirroring_primary_sink_set_ip_and_port(scmirroring_primary_sink, g_peer_ip, g_peer_port); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_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_primary_sink_set_state_changed_cb(scmirroring_primary_sink, scmirroring_sink_state_callback, NULL); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_sink_set_state_changed_cb fail [%d]", ret); + return FALSE; + } + + ret = scmirroring_primary_sink_connect(scmirroring_primary_sink); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("scmirroring_primary_sink_connect fail [%d]", ret); + return FALSE; + } + + g_print("__scmirroring_primary_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 _scmirroring_primary_src_create(void) + { + int ret = SCMIRRORING_ERROR_NONE; + + g_print("Create source handle\n"); + ret = scmirroring_primary_src_create(&scmirroring_primary_sink); + if (ret != SCMIRRORING_ERROR_NONE) { + g_print("Failed to create source handle\n"); + return ret; + } + + g_print("Set state Changed callback function\n"); + ret = scmirroring_primary_src_set_state_changed_cb(scmirroring_primary_sink, scmirroring_source_state_callback, NULL); + if (ret != SCMIRRORING_ERROR_NONE) + g_print("Failed to set state changed callback\n"); + + return ret; + } + + int main(int argc, char *argv[]) + { + 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; + appcore_efl_main(PACKAGE, &argc, &argv, &ops); + - g_loop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(g_loop); - + return 0; + }