...
 
Commits (3)
......@@ -81,6 +81,7 @@ set(LINPHONE_SOURCE_FILES_C
presence.c
proxy.c
quality_reporting.c
recorder.c
remote_provisioning.c
ringtoneplayer.c
siplogin.c
......
......@@ -65,6 +65,7 @@
#include "vcard_private.h"
#include "carddav.h"
#include "linphone/player.h"
#include "linphone/recorder.h"
#include "account_creator_private.h"
#include "tester_utils.h"
......
......@@ -455,6 +455,14 @@ LinphonePlayer * linphone_player_new(void);
void _linphone_player_destroy(LinphonePlayer *player);
/*****************************************************************************
* Recorder interface *
****************************************************************************/
LinphoneRecorder * linphone_recorder_new(void);
void _linphone_recorder_destroy(LinphoneRecorder *recorder);
/*****************************************************************************
* XML UTILITY FUNCTIONS *
****************************************************************************/
......
......@@ -123,7 +123,7 @@ struct _LinphoneProxyConfig
/*use to check if server config has changed between edit() and done()*/
LinphoneAddress *saved_proxy;
LinphoneAddress *saved_identity;
/*---*/
LinphoneAddress *pending_contact; /*use to store previous contact in case of network failure*/
LinphoneEvent *presence_publish_event;
......@@ -604,6 +604,26 @@ struct _LinphonePlayer{
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphonePlayer);
/*****************************************************************************
* Recorder interface *
****************************************************************************/
struct _LinphoneRecorder{
belle_sip_object_t base;
void *user_data;
int (*open)(LinphoneRecorder* recorder, const char *filename, int device_orientation);
int (*start)(LinphoneRecorder* recorder);
int (*pause)(LinphoneRecorder* recorder);
MSRecorderState (*get_state)(LinphoneRecorder* recorder);
void (*close)(LinphoneRecorder* recorder);
void (*destroy)(LinphoneRecorder *recorder);
void (*remove_file)(LinphoneRecorder* recorder, const char *filename);
void *impl;
};
BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneRecorder);
/*****************************************************************************
* XML UTILITY FUNCTIONS *
****************************************************************************/
......
/*
linphone
Copyright (C) 2014 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "c-wrapper/c-wrapper.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
#include <mediastreamer2/msmediarecorder.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/mswebcam.h>
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneRecorder);
BELLE_SIP_INSTANCIATE_VPTR(LinphoneRecorder, belle_sip_object_t,
_linphone_recorder_destroy, // destroy
NULL, // clone
NULL, // marshal
FALSE
);
static int _recorder_open(LinphoneRecorder *obj, const char *filename, int device_orientation);
static int _recorder_start(LinphoneRecorder *obj);
static int _recorder_pause(LinphoneRecorder *obj);
static MSRecorderState _recorder_get_state(LinphoneRecorder *obj);
static void _recorder_close(LinphoneRecorder *obj);
static void _recorder_destroy(LinphoneRecorder *obj);
static void _recorder_remove_file(LinphoneRecorder *obj, const char *filename);
LinphoneRecorder *linphone_core_create_recorder(LinphoneCore *lc, const char *sound_card_name, const char *web_cam_name, const char *video_display_name, void *window_id, MSFileFormat format, const char *video_codec) {
LinphoneRecorder *obj = linphone_recorder_new();
MSSndCard *snd_card;
MSSndCardManager *snd_card_manager = ms_factory_get_snd_card_manager(lc->factory);
MSWebCam *web_cam;
MSWebCamManager *web_cam_manager = ms_factory_get_web_cam_manager(lc->factory);
if (sound_card_name == NULL) sound_card_name = linphone_core_get_capture_device(lc);
snd_card = ms_snd_card_manager_get_card(snd_card_manager, sound_card_name);
if (web_cam_name == NULL) web_cam_name = linphone_core_get_video_device(lc);
web_cam = ms_web_cam_manager_get_cam(web_cam_manager, web_cam_name);
if (video_display_name == NULL) video_display_name = linphone_core_get_video_display_filter(lc);
obj->impl = ms_media_recorder_new(lc->factory, snd_card, web_cam, video_display_name, window_id, format, video_codec);
obj->open = _recorder_open;
obj->start = _recorder_start;
obj->pause = _recorder_pause;
obj->get_state = _recorder_get_state;
obj->close = _recorder_close;
obj->destroy = _recorder_destroy;
obj->remove_file = _recorder_remove_file;
return obj;
}
bool_t linphone_recorder_matroska_supported(void) {
return ms_media_recorder_matroska_supported();
}
static int _recorder_open(LinphoneRecorder *obj, const char *filename, int device_orientation) {
return ms_media_recorder_open((MSMediaRecorder *)obj->impl, filename, device_orientation) ? 0 : -1;
}
static int _recorder_start(LinphoneRecorder *obj) {
return ms_media_recorder_start((MSMediaRecorder *)obj->impl) ? 0 : -1;
}
static int _recorder_pause(LinphoneRecorder *obj) {
ms_media_recorder_pause((MSMediaRecorder *)obj->impl);
return 0;
}
static MSRecorderState _recorder_get_state(LinphoneRecorder *obj) {
return ms_media_recorder_get_state((MSMediaRecorder *)obj->impl);
}
static void _recorder_destroy(LinphoneRecorder *obj) {
ms_media_recorder_free((MSMediaRecorder *)obj->impl);
}
static void _recorder_close(LinphoneRecorder *obj) {
ms_media_recorder_close((MSMediaRecorder *)obj->impl);
}
static void _recorder_remove_file(LinphoneRecorder *obj, const char *filename) {
ms_media_recorder_remove_file((MSMediaRecorder *)obj->impl, filename);
}
LinphoneRecorder * linphone_recorder_new(void) {
LinphoneRecorder *recorder = belle_sip_object_new(LinphoneRecorder);
return recorder;
}
LinphoneRecorder * linphone_recorder_ref(LinphoneRecorder *recorder) {
belle_sip_object_ref(recorder);
return recorder;
}
void linphone_recorder_unref(LinphoneRecorder *recorder) {
belle_sip_object_unref(recorder);
}
void *linphone_recorder_get_user_data(const LinphoneRecorder *recorder) {
return recorder->user_data;
}
void linphone_recorder_set_user_data(LinphoneRecorder *recorder, void *ud) {
recorder->user_data = ud;
}
LinphoneStatus linphone_recorder_open(LinphoneRecorder *obj, const char *filename, int device_orientation){
return obj->open(obj,filename,device_orientation);
}
LinphoneStatus linphone_recorder_start(LinphoneRecorder *obj){
return obj->start(obj);
}
LinphoneStatus linphone_recorder_pause(LinphoneRecorder *obj){
return obj->pause(obj);
}
LinphoneRecorderState linphone_recorder_get_state(LinphoneRecorder *obj){
switch (obj->get_state(obj)) {
case MSRecorderClosed:
default:
return LinphoneRecorderClosed;
case MSRecorderPaused:
return LinphoneRecorderPaused;
case MSRecorderRunning:
return LinphoneRecorderRunning;
}
}
void linphone_recorder_remove_file(LinphoneRecorder *obj, const char *filename){
obj->remove_file(obj, filename);
}
void linphone_recorder_close(LinphoneRecorder *obj){
obj->close(obj);
}
void linphone_recorder_destroy(LinphoneRecorder *obj) {
_linphone_recorder_destroy(obj);
}
void _linphone_recorder_destroy(LinphoneRecorder *recorder) {
if(recorder->destroy) recorder->destroy(recorder);
}
......@@ -55,6 +55,7 @@ set(ROOT_HEADER_FILES
player.h
presence.h
proxy_config.h
recorder.h
ringtoneplayer.h
sipsetup.h
tunnel.h
......@@ -135,7 +136,7 @@ set(LINPHONE_HEADER_FILES ${ROOT_HEADER_FILES} ${C_API_HEADER_FILES} ${ENUMS_HEA
set(LINPHONE_HEADER_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}" PARENT_SCOPE)
# ------------------------------------------------------------------------------
if (IOS AND ENABLE_SHARED)
if (IOS AND ENABLE_SHARED)
#cmake 3.10 seems not able to handle subdirectories for PUBLIC_HEADER. My be rework in the futur
set(DEST_ROOT_DIRECTORY "${CMAKE_INSTALL_PREFIX}/Frameworks/linphone.framework/Headers")
else()
......
......@@ -34,6 +34,7 @@ linphone_include_HEADERS=\
player.h \
presence.h \
proxy_config.h \
recorder.h \
ringtoneplayer.h \
sipsetup.h \
tunnel.h \
......
......@@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "mediastreamer2/msvideo.h"
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/bitratecontrol.h"
#include "mediastreamer2/msmediaplayer.h"
#include "linphone/defs.h"
#include "linphone/types.h"
......@@ -59,6 +60,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "linphone/player.h"
#include "linphone/presence.h"
#include "linphone/proxy_config.h"
#include "linphone/recorder.h"
#include "linphone/ringtoneplayer.h"
#include "linphone/vcard.h"
#include "linphone/video_definition.h"
......@@ -101,10 +103,24 @@ LINPHONE_PUBLIC LinphoneAddress * linphone_core_create_address(LinphoneCore *lc,
* @param sound_card_name Playback sound card. If NULL, the ringer sound card set in #LinphoneCore will be used
* @param video_display_name Video display. If NULL, the video display set in #LinphoneCore will be used
* @param window_id Id of the drawing window. Depend of video out
* @return A pointer on the new instance. NULL if faild.
* @return A pointer on the new instance. NULL if failed.
*/
LINPHONE_PUBLIC LinphonePlayer *linphone_core_create_local_player(LinphoneCore *lc, const char *sound_card_name, const char *video_display_name, void *window_id);
/**
* Create a media file recorder.
* This recorder support WAVE and MATROSKA formats.
* @param lc A #LinphoneCore object
* @param sound_card_name Recording sound card. If NULL, the ringer sound card set in #LinphoneCore will be used
* @param web_cam_name Recording web cam. If NULL, no video will be recorded.
* @param video_display_name Video display. If NULL, the video display set in #LinphoneCore will be used
* @param window_id Id of the drawing window. Depend of video out
* @param format File format we want to record to, MS_FILE_FORMAT_WAVE or MS_FILE_FORMAT_MATROSKA
* @param video_codec Codec of the video if we record video. "vp8" or "h264"
* @return A pointer on the new instance. NULL if failed.
*/
LINPHONE_PUBLIC LinphoneRecorder *linphone_core_create_recorder(LinphoneCore *lc, const char *sound_card_name, const char *web_cam_name, const char *video_display_name, void *window_id, MSFileFormat format, const char *video_codec);
/**
* Creates an empty info message.
* @param lc the #LinphoneCore
......
......@@ -138,6 +138,12 @@ LINPHONE_PUBLIC const char *linphone_tunnel_mode_to_string(LinphoneTunnelMode mo
*/
LINPHONE_PUBLIC bool_t linphone_local_player_matroska_supported(void);
/**
* Check whether Matroksa format is supported by the recorder
* @return TRUE if it is supported
*/
LINPHONE_PUBLIC bool_t linphone_recorder_matroska_supported(void);
/**
* Converts a #LinphoneTransportType enum to a lowercase string.
* @ingroup misc
......
/*
recorder.h
Copyright (C) 2010-2018 Belledonne Communications SARL
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef LINPHONE_RECORDER_H_
#define LINPHONE_RECORDER_H_
#include "linphone/types.h"
#include "mediastreamer2/msinterfaces.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup call_control
* @{
*/
/**
* Acquire a reference to the recorder.
* @param[in] recorder #LinphoneRecorder object.
* @return The same #LinphoneRecorder object.
**/
LINPHONE_PUBLIC LinphoneRecorder * linphone_recorder_ref(LinphoneRecorder *recorder);
/**
* Release reference to the recorder.
* @param[in] recorder #LinphoneRecorder object.
**/
LINPHONE_PUBLIC void linphone_recorder_unref(LinphoneRecorder *recorder);
/**
* Retrieve the user pointer associated with the recorder.
* @param[in] recorder #LinphoneRecorder object.
* @return The user pointer associated with the recorder.
**/
LINPHONE_PUBLIC void *linphone_recorder_get_user_data(const LinphoneRecorder *recorder);
/**
* Assign a user pointer to the recorder.
* @param[in] recorder #LinphoneRecorder object.
* @param[in] ud The user pointer to associate with the recorder.
**/
LINPHONE_PUBLIC void linphone_recorder_set_user_data(LinphoneRecorder *recorder, void *ud);
/**
* Open a file for playing.
* @param[in] obj #LinphoneRecorder object
* @param[in] filename The path to the file to open
*/
LINPHONE_PUBLIC LinphoneStatus linphone_recorder_open(LinphoneRecorder *obj, const char *filename, int device_orientation);
/**
* Start playing a file that has been opened with linphone_recorder_open().
* @param[in] obj #LinphoneRecorder object
* @return 0 on success, a negative value otherwise
*/
LINPHONE_PUBLIC LinphoneStatus linphone_recorder_start(LinphoneRecorder *obj);
/**
* Pause the playing of a file.
* @param[in] obj #LinphoneRecorder object
* @return 0 on success, a negative value otherwise
*/
LINPHONE_PUBLIC LinphoneStatus linphone_recorder_pause(LinphoneRecorder *obj);
/**
* Get the current state of a recorder.
* @param[in] obj #LinphoneRecorder object
* @return The current state of the recorder.
*/
LINPHONE_PUBLIC LinphoneRecorderState linphone_recorder_get_state(LinphoneRecorder *obj);
/**
* Close the opened file.
* @param[in] obj #LinphoneRecorder object
*/
LINPHONE_PUBLIC void linphone_recorder_close(LinphoneRecorder *obj);
/**
* Close the opened file.
* @param[in] obj #LinphoneRecorder object
*/
LINPHONE_PUBLIC void linphone_recorder_remove_file(LinphoneRecorder *obj, const char *filename);
#ifdef __cplusplus
}
#endif
#endif /* LINPHONE_RECORDER_H_ */
......@@ -637,6 +637,22 @@ typedef enum LinphonePlayerState {
LinphonePlayerPlaying /**< The player is playing. */
} LinphonePlayerState;
/**
* Recorder interface.
* @ingroup call_control
**/
typedef struct _LinphoneRecorder LinphoneRecorder;
/**
* The state of a LinphoneRecorder`.
* @ingroup call_control
*/
typedef enum LinphoneRecorderState {
LinphoneRecorderClosed, /**< No file is opened for recording. */
LinphoneRecorderPaused, /**< The recorder is paused. */
LinphoneRecorderRunning /**< The recorder is running. */
} LinphoneRecorderState;
/**
* Presence activity type holding information about a presence activity.
* @ingroup buddy_list
......
......@@ -114,6 +114,7 @@ BELLE_SIP_TYPE_ID(LinphonePresencePerson),
BELLE_SIP_TYPE_ID(LinphonePresenceService),
BELLE_SIP_TYPE_ID(LinphoneProxyConfig),
BELLE_SIP_TYPE_ID(LinphoneRange),
BELLE_SIP_TYPE_ID(LinphoneRecorder),
BELLE_SIP_TYPE_ID(LinphoneTransports),
BELLE_SIP_TYPE_ID(LinphoneTunnel),
BELLE_SIP_TYPE_ID(LinphoneTunnelConfig),
......
......@@ -195,6 +195,7 @@ set(SOURCE_FILES_C
presence_tester.c
proxy_config_tester.c
quality_reporting_tester.c
recorder_tester.c
register_tester.c
remote_provisioning_tester.c
setup_tester.c
......
......@@ -74,6 +74,7 @@ extern test_suite_t presence_test_suite;
extern test_suite_t property_container_test_suite;
extern test_suite_t proxy_config_test_suite;
extern test_suite_t quality_reporting_test_suite;
extern test_suite_t recorder_test_suite;
extern test_suite_t register_test_suite;
extern test_suite_t remote_provisioning_test_suite;
extern test_suite_t setup_test_suite;
......
/*
liblinphone_tester - liblinphone test suite
Copyright (C) 2013 Belledonne Communications SARL
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "liblinphone_tester.h"
#include "tester_utils.h"
#include <mediastreamer2/mediastream.h>
#include <sys/stat.h>
static void record_file(const char *filename, bool_t supported_format, const char *audio_mime, const char *video_mime, MSFileFormat format) {
LinphoneCoreManager *lc_manager = linphone_core_manager_create("marie_rc");
LinphoneRecorder *recorder;
int res = 0;
bool_t res2 = FALSE;
if (strcmp(video_mime, "") != 0) {
linphone_core_set_video_device(lc_manager->lc, liblinphone_tester_mire_id);
if(linphone_core_find_payload_type(lc_manager->lc, video_mime, -1, -1)) {
disable_all_video_codecs_except_one(lc_manager->lc, video_mime);
} else {
ms_warning("call_recording(): the %s payload has not been found. Only sound will be recorded", video_mime);
}
}
recorder = linphone_core_create_recorder(lc_manager->lc, linphone_core_get_ringer_device(lc_manager->lc),
linphone_core_get_video_device(lc_manager->lc), video_stream_get_default_video_renderer(),
0, format, video_mime);
BC_ASSERT_PTR_NOT_NULL(recorder);
if(recorder == NULL) goto fail;
res = linphone_recorder_open(recorder, filename, linphone_core_get_device_rotation(lc_manager->lc));
BC_ASSERT_EQUAL(res, 0, int, "%d");
if(res == -1) goto fail;
LinphoneRecorderState state = linphone_recorder_get_state(recorder);
res2 = state == LinphoneRecorderPaused;
BC_ASSERT_TRUE(res2);
if(!res2) goto fail;
printf("We check if the recorder is in stand by, res2 = %d\n", res2);
res = linphone_recorder_start(recorder);
BC_ASSERT_EQUAL(res, 0, int, "%d");
if(res == -1) goto fail;
state = linphone_recorder_get_state(recorder);
res2 = state == LinphoneRecorderRunning;
BC_ASSERT_TRUE(res2);
printf("We check if the recorder is running, res2 = %d\n", res2);
if(!res2) goto fail;
sleep(5);
linphone_recorder_close(recorder);
state = linphone_recorder_get_state(recorder);
res2 = state == LinphoneRecorderClosed;
BC_ASSERT_TRUE(res2);
printf("We check if the recorder is closed, res2 = %d\n", res2);
if(!res2) goto fail;
res = access(filename, F_OK | W_OK);
BC_ASSERT_EQUAL(res, 0, int, "%d");
printf("We check if the file exists, res = %d\n", res);
if(res == 0) {
struct stat st;
res = stat(filename, &st);
BC_ASSERT_EQUAL(res, 0, int, "%d");
printf("We check if the file can be opened, res = %d\n", res);
res2 = st.st_size > 0;
BC_ASSERT_TRUE(res2);
printf("We check if the file has non zero size, res2 = %d\n", res2);
linphone_recorder_remove_file(recorder, filename);
}
fail:
if(recorder) linphone_recorder_unref(recorder);
if(lc_manager) linphone_core_manager_destroy(lc_manager);
}
static void record_wav_pcm_test(void) {
char *filename = bctbx_strdup_printf("%s/testrecordpcm.wav", bc_tester_get_writable_dir_prefix());
const char *audio_mime = "pcm";
const char *video_mime = "";
record_file(filename, TRUE, audio_mime, video_mime, MS_FILE_FORMAT_WAVE);
ms_free(filename);
}
static void record_mkv_opus_h264_test(void) {
char *filename = bctbx_strdup_printf("%s/testrecordopush264.mkv", bc_tester_get_writable_dir_prefix());
const char *audio_mime = "opus";
const char *video_mime = "h264";
record_file(filename, linphone_recorder_matroska_supported(), audio_mime, video_mime, MS_FILE_FORMAT_MATROSKA);
ms_free(filename);
}
static void record_mkv_opus_vp8_test(void) {
char *filename = bctbx_strdup_printf("%s/testrecordopusvp8.mkv", bc_tester_get_writable_dir_prefix());
const char *audio_mime = "opus";
const char *video_mime = "vp8";
record_file(filename, linphone_recorder_matroska_supported(), audio_mime, video_mime, MS_FILE_FORMAT_MATROSKA);
ms_free(filename);
}
test_t recorder_tests[] = {
TEST_NO_TAG("Recording wave", record_wav_pcm_test),
TEST_NO_TAG("Recording mkv opus+h264", record_mkv_opus_h264_test),
TEST_NO_TAG("Recording mkv opus+VP8", record_mkv_opus_vp8_test)
};
test_suite_t recorder_test_suite = {"Recorder", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each,
sizeof(recorder_tests) / sizeof(test_t), recorder_tests};
......@@ -632,6 +632,7 @@ void liblinphone_tester_add_suites() {
bc_tester_add_suite(&quality_reporting_test_suite);
bc_tester_add_suite(&log_collection_test_suite);
bc_tester_add_suite(&player_test_suite);
bc_tester_add_suite(&recorder_test_suite);
bc_tester_add_suite(&dtmf_test_suite);
bc_tester_add_suite(&cpim_test_suite);
bc_tester_add_suite(&multipart_test_suite);
......