From d67eeda8731b4db5ddae62b1439aef09132e9457 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Mon, 30 Apr 2018 12:52:53 +0200 Subject: [PATCH] Applied snapshot taken callback changes from master --- coreapi/private_functions.h | 1 + include/linphone/api/c-call-cbs.h | 14 ++++ include/linphone/api/c-callbacks.h | 7 ++ src/c-wrapper/api/c-call-cbs.cpp | 9 +++ src/c-wrapper/api/c-call.cpp | 3 + src/call/call-p.h | 1 + src/call/call.cpp | 5 ++ .../session/call-session-listener.h | 2 + src/conference/session/media-session-p.h | 3 + src/conference/session/media-session.cpp | 21 +++++ tester/call_video_tester.c | 76 ++++++++++++++++++- tester/liblinphone_tester.h | 2 + 12 files changed, 141 insertions(+), 3 deletions(-) diff --git a/coreapi/private_functions.h b/coreapi/private_functions.h index 031e00eef..8e6ce8394 100644 --- a/coreapi/private_functions.h +++ b/coreapi/private_functions.h @@ -49,6 +49,7 @@ void linphone_call_notify_stats_updated(LinphoneCall *call, const LinphoneCallSt void linphone_call_notify_info_message_received(LinphoneCall *call, const LinphoneInfoMessage *msg); void linphone_call_notify_ack_processing(LinphoneCall *call, LinphoneHeaders *msg, bool_t is_received); void linphone_call_notify_tmmbr_received(LinphoneCall *call, int stream_index, int tmmbr); +void linphone_call_notify_snapshot_taken(LinphoneCall *call, const char *file_path); LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, const LinphoneCallParams *params, LinphoneProxyConfig *cfg); LinphoneCall * linphone_call_new_incoming(struct _LinphoneCore *lc, const LinphoneAddress *from, const LinphoneAddress *to, LinphonePrivate::SalCallOp *op); diff --git a/include/linphone/api/c-call-cbs.h b/include/linphone/api/c-call-cbs.h index 3901702fc..5ef4d70b8 100644 --- a/include/linphone/api/c-call-cbs.h +++ b/include/linphone/api/c-call-cbs.h @@ -173,6 +173,20 @@ LINPHONE_PUBLIC LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_recei */ LINPHONE_PUBLIC void linphone_call_cbs_set_tmmbr_received(LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb); +/** + * Get the snapshot taken callback. + * @param[in] cbs LinphoneCallCbs object. + * @return The current snapshot taken callback. + */ +LINPHONE_PUBLIC LinphoneCallCbsSnapshotTakenCb linphone_call_cbs_get_snapshot_taken(LinphoneCallCbs *cbs); + +/** + * Set the snapshot taken callback. + * @param[in] cbs LinphoneCallCbs object. + * @param[in] cb The snapshot taken callback to be used. + */ +LINPHONE_PUBLIC void linphone_call_cbs_set_snapshot_taken(LinphoneCallCbs *cbs, LinphoneCallCbsSnapshotTakenCb cb); + /** * @} */ diff --git a/include/linphone/api/c-callbacks.h b/include/linphone/api/c-callbacks.h index 6a707e7b1..f3a29a94a 100644 --- a/include/linphone/api/c-callbacks.h +++ b/include/linphone/api/c-callbacks.h @@ -95,6 +95,13 @@ typedef void (*LinphoneCallCbsAckProcessingCb)(LinphoneCall *call, LinphoneHeade */ typedef void (*LinphoneCallCbsTmmbrReceivedCb)(LinphoneCall *call, int stream_index, int tmmbr); +/** + * Callback for notifying a snapshot taken. + * @param call LinphoneCall for which the snapshot was taken + * @param filepath the name of the saved file + */ +typedef void (*LinphoneCallCbsSnapshotTakenCb)(LinphoneCall *call, const char *filepath); + /** * @} **/ diff --git a/src/c-wrapper/api/c-call-cbs.cpp b/src/c-wrapper/api/c-call-cbs.cpp index 903dfa26a..3280c3e0b 100644 --- a/src/c-wrapper/api/c-call-cbs.cpp +++ b/src/c-wrapper/api/c-call-cbs.cpp @@ -34,6 +34,7 @@ struct _LinphoneCallCbs { LinphoneCallCbsTransferStateChangedCb transferStateChangedCb; LinphoneCallCbsAckProcessingCb ackProcessing; LinphoneCallCbsTmmbrReceivedCb tmmbrReceivedCb; + LinphoneCallCbsSnapshotTakenCb snapshotTakenCb; }; BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneCallCbs); @@ -133,3 +134,11 @@ LinphoneCallCbsTmmbrReceivedCb linphone_call_cbs_get_tmmbr_received (LinphoneCal void linphone_call_cbs_set_tmmbr_received (LinphoneCallCbs *cbs, LinphoneCallCbsTmmbrReceivedCb cb) { cbs->tmmbrReceivedCb = cb; } + +LinphoneCallCbsSnapshotTakenCb linphone_call_cbs_get_snapshot_taken(LinphoneCallCbs *cbs) { + return cbs->snapshotTakenCb; +} + +void linphone_call_cbs_set_snapshot_taken(LinphoneCallCbs *cbs, LinphoneCallCbsSnapshotTakenCb cb) { + cbs->snapshotTakenCb = cb; +} diff --git a/src/c-wrapper/api/c-call.cpp b/src/c-wrapper/api/c-call.cpp index c3f05d29a..1eae338a6 100644 --- a/src/c-wrapper/api/c-call.cpp +++ b/src/c-wrapper/api/c-call.cpp @@ -184,6 +184,9 @@ void linphone_call_notify_tmmbr_received (LinphoneCall *call, int stream_index, NOTIFY_IF_EXIST(TmmbrReceived, tmmbr_received, call, stream_index, tmmbr) } +void linphone_call_notify_snapshot_taken(LinphoneCall *call, const char *file_path) { + NOTIFY_IF_EXIST(SnapshotTaken, snapshot_taken, call, file_path) +} // ============================================================================= // Public functions. diff --git a/src/call/call-p.h b/src/call/call-p.h index 0477198df..488df87aa 100644 --- a/src/call/call-p.h +++ b/src/call/call-p.h @@ -111,6 +111,7 @@ private: bool isPlayingRingbackTone (const std::shared_ptr &session) override; void onRealTimeTextCharacterReceived (const std::shared_ptr &session, RealtimeTextReceivedCharacter *character) override; void onTmmbrReceived(const std::shared_ptr &session, int streamIndex, int tmmbr) override; + void onSnapshotTaken(const std::shared_ptr &session, const char *file_path) override; mutable LinphonePlayer *player = nullptr; diff --git a/src/call/call.cpp b/src/call/call.cpp index 6d51ce781..e57c788ea 100644 --- a/src/call/call.cpp +++ b/src/call/call.cpp @@ -496,6 +496,11 @@ void CallPrivate::onTmmbrReceived (const shared_ptr &session, int s linphone_call_notify_tmmbr_received(L_GET_C_BACK_PTR(q), streamIndex, tmmbr); } +void CallPrivate::onSnapshotTaken(const shared_ptr &session, const char *file_path) { + L_Q(); + linphone_call_notify_snapshot_taken(L_GET_C_BACK_PTR(q), file_path); +} + // ============================================================================= Call::Call (CallPrivate &p, shared_ptr core) : Object(p), CoreAccessor(core) { diff --git a/src/conference/session/call-session-listener.h b/src/conference/session/call-session-listener.h index edc634f22..3b9c20668 100644 --- a/src/conference/session/call-session-listener.h +++ b/src/conference/session/call-session-listener.h @@ -55,6 +55,7 @@ public: virtual void onInfoReceived (const std::shared_ptr &session, const LinphoneInfoMessage *im) {} virtual void onNoMediaTimeoutCheck (const std::shared_ptr &session, bool oneSecondElapsed) {} virtual void onTmmbrReceived (const std::shared_ptr &session, int streamIndex, int tmmbr) {} + virtual void onSnapshotTaken(const std::shared_ptr &session, const char *file_path) {} virtual void onEncryptionChanged (const std::shared_ptr &session, bool activated, const std::string &authToken) {} @@ -80,6 +81,7 @@ public: virtual bool isPlayingRingbackTone (const std::shared_ptr &session) { return false; } virtual void onRealTimeTextCharacterReceived (const std::shared_ptr &session, RealtimeTextReceivedCharacter *data) {} + }; LINPHONE_END_NAMESPACE diff --git a/src/conference/session/media-session-p.h b/src/conference/session/media-session-p.h index 7013e7b18..efdfe04fd 100644 --- a/src/conference/session/media-session-p.h +++ b/src/conference/session/media-session-p.h @@ -106,6 +106,9 @@ public: // CoreListener void onNetworkReachable (bool sipNetworkReachable, bool mediaNetworkReachable) override; + // Call listener + void snapshotTakenCb(void *userdata, struct _MSFilter *f, unsigned int id, void *arg); + private: static OrtpJitterBufferAlgorithm jitterBufferNameToAlgo (const std::string &name); diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index 694ef27fd..69dda5acb 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4364,11 +4364,30 @@ void MediaSession::resetFirstVideoFrameDecoded () { ms_filter_call_method_noarg(d->videoStream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION); } +void MediaSessionPrivate::snapshotTakenCb(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) { +#ifdef VIDEO_ENABLED + L_Q(); + if (id == MS_JPEG_WRITER_SNAPSHOT_TAKEN) { + const char *filepath = (const char *) arg; + listener->onSnapshotTaken(q->getSharedFromThis(), filepath); + } +#endif +} + +#ifdef VIDEO_ENABLED +static void snapshot_taken(void *userdata, struct _MSFilter *f, unsigned int id, void *arg) { + MediaSessionPrivate *d = (MediaSessionPrivate *)userdata; + d->snapshotTakenCb(userdata, f, id, arg); +} +#endif + LinphoneStatus MediaSession::takePreviewSnapshot (const string& file) { #ifdef VIDEO_ENABLED L_D(); if (d->videoStream && d->videoStream->local_jpegwriter) { + ms_filter_clear_notify_callback(d->videoStream->jpegwriter); const char *filepath = file.empty() ? nullptr : file.c_str(); + ms_filter_add_notify_callback(d->videoStream->local_jpegwriter, snapshot_taken, d, TRUE); return ms_filter_call_method(d->videoStream->local_jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void *)filepath); } lWarning() << "Cannot take local snapshot: no currently running video stream on this call"; @@ -4380,7 +4399,9 @@ LinphoneStatus MediaSession::takeVideoSnapshot (const string& file) { #ifdef VIDEO_ENABLED L_D(); if (d->videoStream && d->videoStream->jpegwriter) { + ms_filter_clear_notify_callback(d->videoStream->jpegwriter); const char *filepath = file.empty() ? nullptr : file.c_str(); + ms_filter_add_notify_callback(d->videoStream->jpegwriter, snapshot_taken, d, TRUE); return ms_filter_call_method(d->videoStream->jpegwriter, MS_JPEG_WRITER_TAKE_SNAPSHOT, (void *)filepath); } lWarning() << "Cannot take snapshot: no currently running video stream on this call"; diff --git a/tester/call_video_tester.c b/tester/call_video_tester.c index 51d87b03c..89bbc22c5 100644 --- a/tester/call_video_tester.c +++ b/tester/call_video_tester.c @@ -1693,6 +1693,15 @@ static void video_call_recording_vp8_test(void) { record_call("recording", TRUE, "VP8"); } +static void snapshot_taken(LinphoneCall *call, const char *filepath) { + char *filename = bc_tester_file("snapshot.jpeg"); + LinphoneCore *lc = linphone_call_get_core(call); + stats *callstats = get_stats(lc); + BC_ASSERT_STRING_EQUAL(filepath, filename); + callstats->number_of_snapshot_taken++; + ms_free(filename); +} + static void video_call_snapshot(void) { LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); @@ -1700,7 +1709,6 @@ static void video_call_snapshot(void) { LinphoneCallParams *paulineParams = linphone_core_create_call_params(pauline->lc, NULL); LinphoneCall *callInst = NULL; char *filename = bc_tester_file("snapshot.jpeg"); - int dummy = 0; bool_t call_succeeded = FALSE; linphone_core_enable_video_capture(marie->lc, TRUE); @@ -1712,12 +1720,73 @@ static void video_call_snapshot(void) { BC_ASSERT_TRUE(call_succeeded = call_with_params(marie, pauline, marieParams, paulineParams)); BC_ASSERT_PTR_NOT_NULL(callInst = linphone_core_get_current_call(marie->lc)); - if((call_succeeded == TRUE) && (callInst != NULL)) { + if (call_succeeded == TRUE && callInst != NULL) { + LinphoneCall *marie_call = linphone_core_get_current_call(marie->lc); + LinphoneCallCbs *marie_call_cbs = linphone_factory_create_call_cbs(linphone_factory_get()); + BC_ASSERT_PTR_NOT_NULL(marie_call); + linphone_call_cbs_set_snapshot_taken(marie_call_cbs, snapshot_taken); + linphone_call_add_callbacks(marie_call, marie_call_cbs); + linphone_call_cbs_unref(marie_call_cbs); int jpeg_support = linphone_call_take_video_snapshot(callInst, filename); if (jpeg_support < 0) { ms_warning("No jpegwriter support!"); } else { - wait_for_until(marie->lc, pauline->lc, &dummy, 1, 5000); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_snapshot_taken,1)); + BC_ASSERT_EQUAL(ortp_file_exist(filename), 0, int, "%d"); + remove(filename); + } + end_call(marie, pauline); + } + ms_free(filename); + linphone_call_params_unref(marieParams); + linphone_call_params_unref(paulineParams); + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + +static void video_call_snapshots(void) { + LinphoneCoreManager *marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + LinphoneCallParams *marieParams = linphone_core_create_call_params(marie->lc, NULL); + LinphoneCallParams *paulineParams = linphone_core_create_call_params(pauline->lc, NULL); + LinphoneCall *callInst = NULL; + char *filename = bc_tester_file("snapshot.jpeg"); + bool_t call_succeeded = FALSE; + int dummy = 0; + + linphone_core_enable_video_capture(marie->lc, TRUE); + linphone_core_enable_video_display(marie->lc, TRUE); + linphone_core_enable_video_capture(pauline->lc, TRUE); + linphone_core_enable_video_display(pauline->lc, FALSE); + linphone_call_params_enable_video(marieParams, TRUE); + linphone_call_params_enable_video(paulineParams, TRUE); + + BC_ASSERT_TRUE(call_succeeded = call_with_params(marie, pauline, marieParams, paulineParams)); + BC_ASSERT_PTR_NOT_NULL(callInst = linphone_core_get_current_call(marie->lc)); + if (call_succeeded == TRUE && callInst != NULL) { + LinphoneCall *marie_call = linphone_core_get_current_call(marie->lc); + LinphoneCallCbs *marie_call_cbs = linphone_factory_create_call_cbs(linphone_factory_get()); + BC_ASSERT_PTR_NOT_NULL(marie_call); + linphone_call_cbs_set_snapshot_taken(marie_call_cbs, snapshot_taken); + linphone_call_add_callbacks(marie_call, marie_call_cbs); + linphone_call_cbs_unref(marie_call_cbs); + int jpeg_support = linphone_call_take_video_snapshot(callInst, filename); + if (jpeg_support < 0) { + ms_warning("No jpegwriter support!"); + } else { + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_snapshot_taken,1)); + BC_ASSERT_EQUAL(ortp_file_exist(filename), 0, int, "%d"); + remove(filename); + + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 1000); + linphone_call_take_video_snapshot(callInst, filename); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_snapshot_taken,2)); + BC_ASSERT_EQUAL(ortp_file_exist(filename), 0, int, "%d"); + remove(filename); + + wait_for_until(marie->lc, pauline->lc, &dummy, 1, 1000); + linphone_call_take_video_snapshot(callInst, filename); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_snapshot_taken,3)); BC_ASSERT_EQUAL(ortp_file_exist(filename), 0, int, "%d"); remove(filename); } @@ -2214,6 +2283,7 @@ test_t call_video_tests[] = { TEST_NO_TAG("Video call recording (H264)", video_call_recording_h264_test), TEST_NO_TAG("Video call recording (VP8)", video_call_recording_vp8_test), TEST_NO_TAG("Snapshot", video_call_snapshot), + TEST_NO_TAG("Snapshots", video_call_snapshots), TEST_NO_TAG("Video call with early media and no matching audio codecs", video_call_with_early_media_no_matching_audio_codecs), TEST_NO_TAG("DTLS SRTP video call", dtls_srtp_video_call), TEST_ONE_TAG("DTLS SRTP ice video call", dtls_srtp_ice_video_call, "ICE"), diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 0979de45c..ca5c6b251 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -291,6 +291,8 @@ typedef struct _stats { int number_of_participants_removed; int number_of_subject_changed; int number_of_participant_devices_added; + + int number_of_snapshot_taken; }stats;