我正在尝试编写一个简单的应用程序来使用 C 中的本机应用程序开发在我的银河手表上录制音频。
到目前为止,当我启动应用程序并有一个开始和停止录制的按钮时,我就到了这个阶段。
由于某种原因,我无法让记录器工作,它返回rerror -38
,这是内部错误,在日志中我可以看到:
mm_camcorder_audiorec.c: _mmcamcorder_audio_command(530) > file delete(/opt/usr/home/owner/apps_rw/org.example.audiorecorder/data/AUDIO-2019-11-24_01:15:51.3gp)
但我不知道为什么它会在 recorder_commit 上被删除。
我错过了什么?你能帮我吗?
应用程序代码:
#include <app.h>
#include <stddef.h>
#include <privacy_privilege_manager.h>
// Functions for creating and managing user interface elements. Here are all the widgets,
// such as: windows, buttons, etc.
#include <Elementary.h>
//Functions for using callback for hardware Back button and for
//using extended widgets for a circle screen
#include <efl_extension.h>
#include "audiorecorder.h"
#include <recorder.h>
#include <camera.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
typedef struct _UIData
{
Evas_Object *win;
Evas_Object *box;
Evas_Object *icon;
Evas_Object *button;
} UIData;
#define TEXT_BUF_SIZE 256
#define FILENAME_PREFIX "AUDIO"
#define NUMBER_OF_PRIVILEGES 3
#define START_RECORD_IMAGE_PATH "images/start-recording.jpg"
#define STOP_RECORD_IMAGE_PATH "images/stop-recording.png"
static recorder_h g_recorder;
bool permission_granted = false;
int user_clicked = 0;
static void
_state_changed_cb(recorder_state_e previous,
recorder_state_e current,
bool by_policy, void *user_data)
{
dlog_print(DLOG_INFO, LOG_TAG,
"_recorder_state_changed_cb (prev: %d, curr: %d)\n",
previous,
current);
}
static void
_recorder_recording_limit_reached_cb(
recorder_recording_limit_type_e type,
void *user_data)
{
dlog_print(DLOG_DEBUG, LOG_TAG, "Recording limit reached: %d\n", type);
}
/* Check the audio recorder state */
static bool
_recorder_expect_state(recorder_h recorder,
recorder_state_e expected_state)
{
recorder_state_e state;
int error_code = recorder_get_state(recorder, &state);
dlog_print(DLOG_INFO, LOG_TAG,
"recorder state = %d, expected recorder state = %d, error_code = %d",
state, expected_state, error_code);
if (state == expected_state)
return true;
return false;
}
static void
_win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
UIData *ui = data;
elm_win_lower(ui->win);
}
static void
app_get_resource(const char *edj_file_in, char *edj_path_out, int edj_path_max)
{
char *res_path = app_get_resource_path();
if (res_path)
{
snprintf(edj_path_out, edj_path_max, "%s%s", res_path, edj_file_in);
free(res_path);
}
}
static void
_icon_create(UIData *ui)
{
dlog_print(DLOG_INFO, LOG_TAG, "icon create");
char image_path[PATH_MAX] =
{ 0, };
ui->icon = elm_image_add(ui->button);
elm_image_resizable_set(ui->icon, EINA_TRUE, EINA_TRUE);
app_get_resource(START_RECORD_IMAGE_PATH, image_path, (int) PATH_MAX);
int error_code = elm_image_file_set(ui->icon, image_path, NULL);
dlog_print(DLOG_INFO, LOG_TAG, "res path: %s error_code: %d", image_path, error_code);
evas_object_show(ui->icon);
}
static void
_button_create(UIData *ui)
{
dlog_print(DLOG_INFO, LOG_TAG, "button create");
ui->button = elm_button_add(ui->box);
_icon_create(ui);
elm_object_style_set(ui->button, "circle");
evas_object_size_hint_weight_set(ui->button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(ui->button, 0.5, 0.4);
evas_object_size_hint_min_set(ui->button, ELM_SCALE_SIZE(90), ELM_SCALE_SIZE(90));
elm_object_content_set(ui->button, ui->icon);
evas_object_show(ui->button);
}
static void
_box_create(UIData *ui)
{
dlog_print(DLOG_INFO, LOG_TAG, "box create");
ui->box = elm_box_add(ui->win);
evas_object_size_hint_weight_set(ui->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
_button_create(ui);
elm_object_content_set(ui->box, ui->button);
elm_box_pack_end(ui->box, ui->button);
evas_object_show(ui->box);
}
static void
_window_create(UIData *ui)
{
dlog_print(DLOG_INFO, LOG_TAG, "window create");
// Create and configure the main window
ui->win = elm_win_util_standard_add(NULL, NULL);
// Create a conformant - in this case, the main container in the application,
// which is also the interface between the application and
// system elements, such as a keyboard.
_box_create(ui);
// Set the size of the conformant widget the same as the size of the window
elm_win_resize_object_add(ui->win, ui->box);
//Register the function that will be called
//when you press the hardware Back button
eext_object_event_callback_add(ui->win, EEXT_CALLBACK_BACK, _win_back_cb, ui);
// /Always display the window only after the entire base
// user interface will be displayed.
evas_object_show(ui->win);
}
static void permission_request_cb(ppm_call_cause_e cause,
ppm_request_result_e result,
const char *privilege,
void *user_data)
{
dlog_print(DLOG_INFO, LOG_TAG, "callback called for privilege: %s with cause: %d, the result was: %d", privilege,
cause,
result);
user_clicked++;
}
void *func(void *arg)
{
while (user_clicked < NUMBER_OF_PRIVILEGES)
{
dlog_print(DLOG_INFO, LOG_TAG, "waiting for user to accept all privileges, so far accepted: %d", user_clicked);
sleep(1);
}
return 0;
}
static void _button_click_cb(void *data, Evas_Object *button, void *ev)
{
UIData *ui = data;
int error_code = 0;
dlog_print(DLOG_INFO, LOG_TAG, "clicked button!");
char image_path[PATH_MAX] = { 0, };
const char *image;
const char *group;
char *path = NULL;
recorder_state_e state;
elm_image_file_get(ui->icon, &image, &group);
dlog_print(DLOG_INFO, LOG_TAG, "file get, image: %s, group: %s", image, group);
if (strstr(image, "start") != NULL) {
app_get_resource(STOP_RECORD_IMAGE_PATH, image_path, (int) PATH_MAX);
error_code = elm_image_file_set(ui->icon, image_path, NULL);
dlog_print(DLOG_INFO, LOG_TAG, "setting icon to stop, error code: %d", error_code);
dlog_print(DLOG_INFO, LOG_TAG, "starting recorder");
if (_recorder_expect_state(g_recorder, RECORDER_STATE_READY)
|| _recorder_expect_state(g_recorder, RECORDER_STATE_PAUSED))
{
error_code = recorder_start(g_recorder);
dlog_print(DLOG_INFO, LOG_TAG, "starting recorder result: %d", error_code);
}
else
{
recorder_get_state(g_recorder, &state);
dlog_print(DLOG_INFO, LOG_TAG, "Failure, recorder in wrong state = %d", state);
}
}
else if(strstr(image, "stop") != NULL)
{
app_get_resource(START_RECORD_IMAGE_PATH, image_path, (int) PATH_MAX);
error_code = elm_image_file_set(ui->icon, image_path, NULL);
dlog_print(DLOG_INFO, LOG_TAG, "setting icon to start, error code: %d", error_code);
/* Stop the recorder and save the recorded data to a file */
if (_recorder_expect_state(g_recorder, RECORDER_STATE_RECORDING)
|| _recorder_expect_state(g_recorder, RECORDER_STATE_PAUSED))
{
error_code = recorder_get_filename(g_recorder, &path);
dlog_print(DLOG_INFO, LOG_TAG, "going to save audio to file %s error code: %d", path, error_code);
error_code = recorder_commit(g_recorder);
if (error_code != RECORDER_ERROR_NONE)
{
dlog_print(DLOG_INFO, LOG_TAG, "Failure, error code = %d", error_code);
recorder_cancel(g_recorder);
}
}
else
{
recorder_get_state(g_recorder, &state);
dlog_print(DLOG_INFO, LOG_TAG, "Failure, recorder in wrong state = %d", state);
}
}
}
static bool
_app_create_cb(void *data)
{
UIData *ui = data;
_window_create(ui);
evas_object_smart_callback_add(ui->button, "clicked", _button_click_cb, ui);
return true;
}
static void
_app_control_cb(app_control_h app_control, void *data)
{
/* Handle the launch request. */
}
static void
_app_pause_cb(void *data)
{
/* Take necessary actions when the application becomes invisible. */
}
static void
_app_resume_cb(void *data)
{
ppm_check_result_e privilege_results_array[NUMBER_OF_PRIVILEGES];
const char *privilege_array[NUMBER_OF_PRIVILEGES];
pthread_t pid;
char *recorder_privilege = "http://tizen.org/privilege/recorder";
char *media_storage_privilege = "http://tizen.org/privilege/mediastorage";
char *ex_media_storage_privilege = "http://tizen.org/privilege/externalstorage";
privilege_array[0] = malloc(strlen(recorder_privilege) + 1);
privilege_array[1] = malloc(strlen(media_storage_privilege) + 1);
privilege_array[2] = malloc(strlen(ex_media_storage_privilege) + 1);
strcpy((char*) privilege_array[0], recorder_privilege);
strcpy((char*) privilege_array[1], media_storage_privilege);
strcpy((char*) privilege_array[2], ex_media_storage_privilege);
int result = ppm_check_permissions(privilege_array, NUMBER_OF_PRIVILEGES, privilege_results_array);
dlog_print(DLOG_INFO, LOG_TAG, "checking permission for recorder. Result: %d", result);
for (int i = 0; i < NUMBER_OF_PRIVILEGES; i++)
{
switch (privilege_results_array[i])
{
case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ALLOW:
dlog_print(DLOG_INFO, LOG_TAG, "Privilege: %s, Allowed!", privilege_array[i]);
break;
case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_DENY:
dlog_print(DLOG_INFO, LOG_TAG, "Privilege: %s, Denied!", privilege_array[i]);
break;
case PRIVACY_PRIVILEGE_MANAGER_CHECK_RESULT_ASK:
dlog_print(DLOG_INFO, LOG_TAG, "Privilege: %s, Gotta ask for this privilege!", privilege_array[i]);
ppm_request_permission(privilege_array[i], permission_request_cb, NULL);
break;
}
}
pthread_create(&pid, NULL, func, NULL);
}
static void _app_terminate_cb(void *data)
{
UIData *ui = data;
//Before closing the application, delete the main widget (window),
// then all "children" widgets of this window (all widgets of this application) will be deleted.
evas_object_del(ui->win);
/* Release all resources. */
int error_code = recorder_unset_recording_limit_reached_cb(g_recorder);
error_code = recorder_unprepare(g_recorder);
error_code = recorder_unset_state_changed_cb(g_recorder);
error_code = recorder_destroy(g_recorder);
}
int main(int argc, char *argv[])
{
char filename[256] =
{ '\0' };
struct tm localtime =
{ 0 };
time_t rawtime = time(NULL);
int ret = 0;
size_t size = 0;
dlog_print(DLOG_INFO, LOG_TAG, "main");
UIData ui =
{ 0, };
ui_app_lifecycle_callback_s lifecycle_callbacks =
{ 0, };
/* Create the audio recorder handle */
int error_code = recorder_create_audiorecorder(&g_recorder);
if (error_code == RECORDER_ERROR_NONE)
dlog_print(DLOG_INFO, LOG_TAG, "successfully created audiorecorder error code = %d", error_code);
else
dlog_print(DLOG_ERROR, LOG_TAG, "Failure creating audiorecorder error code = %d", error_code);
error_code = recorder_set_state_changed_cb(g_recorder, _state_changed_cb, NULL);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_set_state_changed_cb, error code = %d", error_code);
/* Set the audio encoder */
error_code = recorder_set_audio_encoder(g_recorder, RECORDER_AUDIO_CODEC_AAC);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_set_audio_encoder, error code = %d", error_code);
/* Set video encoder */
error_code = recorder_set_video_encoder(g_recorder, RECORDER_VIDEO_CODEC_MPEG4);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_set_video_encoder, error code = %d", error_code);
/* Set the maximum file size to unlimited 10240 (kB) - 10 mb */
error_code = recorder_attr_set_size_limit(g_recorder, 10240);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_attr_set_size_limit, error code = %d", error_code);
/* Set the audio encoder bitrate */
error_code = recorder_attr_set_audio_encoder_bitrate(g_recorder, 28800);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_attr_set_audio_encoder_bitrate, error code = %d", error_code);
/* Set the audio device to microphone */
error_code = recorder_attr_set_audio_device(g_recorder, RECORDER_AUDIO_DEVICE_MIC);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_attr_set_audio_device, error code = %d", error_code);
/* Set the audio sample rate */
error_code = recorder_attr_set_audio_samplerate(g_recorder, 44100);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_attr_set_audio_samplerate, error code = %d", error_code);
/* Set the file format according to the audio encoder */
error_code = recorder_set_file_format(g_recorder, RECORDER_FILE_FORMAT_3GP);
dlog_print(DLOG_INFO, LOG_TAG, "setting recorder_set_file_format, error code = %d", error_code);
/* Create the file name */
dlog_print(DLOG_INFO, LOG_TAG, "data path = %s", app_get_data_path());
if (localtime_r(&rawtime, &localtime) != NULL)
{
size = snprintf(filename, sizeof(filename),
"%s%s-%04i-%02i-%02i_%02i:%02i:%02i.3gp",
app_get_data_path(),
FILENAME_PREFIX,
localtime.tm_year + 1900, localtime.tm_mon + 1,
localtime.tm_mday,
localtime.tm_hour, localtime.tm_min,
localtime.tm_sec);
}
else
{
dlog_print(DLOG_INFO, LOG_TAG, "failed to save audio in a file");
}
/* Set the full path and file name */
/* Set the file name according to the file format */
error_code = recorder_set_filename(g_recorder, filename);
dlog_print(DLOG_INFO, LOG_TAG, "setting file name to: %s, error code = %d",
filename,
error_code);
error_code = recorder_set_recording_limit_reached_cb(g_recorder,
_recorder_recording_limit_reached_cb,
NULL);
dlog_print(DLOG_INFO, LOG_TAG, "setting limit reached callback, error code = %d", error_code);
dlog_print(DLOG_INFO, LOG_TAG, "preparing recorder");
error_code = recorder_prepare(g_recorder);
dlog_print(DLOG_INFO, LOG_TAG, "preparing recorder result: %d", error_code);
lifecycle_callbacks.create = _app_create_cb;
lifecycle_callbacks.terminate = _app_terminate_cb;
lifecycle_callbacks.pause = _app_pause_cb;
lifecycle_callbacks.resume = _app_resume_cb;
lifecycle_callbacks.app_control = _app_control_cb;
ret = ui_app_main(argc, argv, &lifecycle_callbacks, &ui);
if (ret != APP_ERROR_NONE)
{
dlog_print(DLOG_ERROR, LOG_TAG, "watch_app_main() is failed. err = %d",
ret);
}
return ret;
}