Check record privilege in audio_in_create 80/70980/3 accepted/tizen/common/20160526.145837 accepted/tizen/ivi/20160602.020553 accepted/tizen/mobile/20160602.020429 accepted/tizen/tv/20160602.020527 accepted/tizen/wearable/20160602.020506 submit/tizen/20160524.060031
authorMok Jeongho <jho.mok@samsung.com>
Mon, 23 May 2016 08:52:10 +0000 (17:52 +0900)
committerMok Jeongho <jho.mok@samsung.com>
Tue, 24 May 2016 03:38:44 +0000 (12:38 +0900)
Previously record privilege was checked in prepare state
when pulse record stream is created, which is wrong.
So now, we check previlege in audio_in_create
with newly created pulse api(pa_context_check_privilege).

[Version] 0.3.35
[Profile] Common
[Issue Type] Privilege

Change-Id: I696f5a861adcce0b43796f52646ed0cc11a1a18b

packaging/capi-media-audio-io.spec
src/cpp/CAudioInput.cpp

index 305624a..6c38ccb 100644 (file)
@@ -1,6 +1,6 @@
 Name:           capi-media-audio-io
 Summary:        An Audio Input & Audio Output library in Tizen Native API
-Version:        0.3.34
+Version:        0.3.35
 Release:        0
 Group:          Multimedia/API
 License:        Apache-2.0
index 453b846..a0e9d41 100644 (file)
  */
 
 
+#include <pulse/pulseaudio.h>
 #include "CAudioIODef.h"
 
+#define RECORDER_PRIVILEGE "http://tizen.org/privilege/recorder"
+#define CLIENT_NAME "AUDIO_IO_PA_CLIENT"
 
 using namespace std;
 using namespace tizen_media_audio;
 
+struct PrivilegeData {
+    bool isPrivilegeAllowed;
+    pa_threaded_mainloop *paMainloop;
+};
 
 /**
  * class CAudioInput inherited by CAudioIO
@@ -91,6 +98,97 @@ bool CAudioInput::__IsReady() {
     return CAudioIO::IsReady();
 }
 
+static void __contextStateChangeCb(pa_context* c, void* user_data) {
+    pa_threaded_mainloop *paMainloop = static_cast<pa_threaded_mainloop*>(user_data);
+    assert(paMainloop);
+    assert(c);
+
+    switch (pa_context_get_state(c)) {
+    case PA_CONTEXT_READY:
+        AUDIO_IO_LOGD("The context is ready");
+        pa_threaded_mainloop_signal(paMainloop, 0);
+        break;
+
+    case PA_CONTEXT_FAILED:
+    case PA_CONTEXT_TERMINATED:
+        AUDIO_IO_LOGD("The context is lost");
+        pa_threaded_mainloop_signal(paMainloop, 0);
+        break;
+
+    case PA_CONTEXT_UNCONNECTED:
+    case PA_CONTEXT_CONNECTING:
+    case PA_CONTEXT_AUTHORIZING:
+    case PA_CONTEXT_SETTING_NAME:
+        break;
+    }
+}
+
+static void __checkPrivilegeCb(pa_context *c, int success, void *user_data) {
+    AUDIO_IO_LOGD("pa_context[%p], success[%d], user_data[%p]", c, success, user_data);
+    assert(c);
+    assert(user_data);
+
+    PrivilegeData* prData= static_cast<PrivilegeData*>(user_data);
+    prData->isPrivilegeAllowed = success ? true : false;
+
+    pa_threaded_mainloop_signal(prData->paMainloop, 0);
+}
+
+static bool __IsPrivilegeAllowed() {
+    pa_operation *o;
+    pa_context *c;
+    int err = 0;
+    PrivilegeData prData;
+
+    prData.paMainloop = pa_threaded_mainloop_new();
+    if (prData.paMainloop == NULL)
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_threaded_mainloop_new()");
+    c = pa_context_new(pa_threaded_mainloop_get_api(prData.paMainloop), CLIENT_NAME);
+    if (c == NULL)
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_new()");
+
+    pa_context_set_state_callback(c, __contextStateChangeCb, prData.paMainloop);
+
+    if (pa_context_connect(c, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_OUT_OF_MEMORY, "Failed pa_context_connect()");
+
+    pa_threaded_mainloop_lock(prData.paMainloop);
+
+    if (pa_threaded_mainloop_start(prData.paMainloop) < 0) {
+        pa_threaded_mainloop_unlock(prData.paMainloop);
+        THROW_ERROR_MSG(CAudioError::EError::ERROR_FAILED_OPERATION, "Failed pa_threaded_mainloop_start()");
+    }
+
+    while (true) {
+        pa_context_state_t state;
+        state = pa_context_get_state(c);
+
+        if (state == PA_CONTEXT_READY)
+            break;
+
+        if (!PA_CONTEXT_IS_GOOD(state)) {
+            err = pa_context_errno(c);
+            pa_threaded_mainloop_unlock(prData.paMainloop);
+            THROW_ERROR_MSG_FORMAT(CAudioError::EError::ERROR_INTERNAL_OPERATION, "pa_context's state is not good : err[%d]", err);
+        }
+
+        /* Wait until the context is ready */
+        pa_threaded_mainloop_wait(prData.paMainloop);
+    }
+
+    o = pa_context_check_privilege(c, RECORDER_PRIVILEGE, __checkPrivilegeCb, &prData);
+    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
+        pa_threaded_mainloop_wait(prData.paMainloop);
+
+    pa_threaded_mainloop_unlock(prData.paMainloop);
+    pa_threaded_mainloop_stop(prData.paMainloop);
+    pa_context_disconnect(c);
+    pa_context_unref(c);
+    pa_threaded_mainloop_free(prData.paMainloop);
+
+    return prData.isPrivilegeAllowed;
+}
+
 void CAudioInput::initialize() throw(CAudioError) {
     if (__IsInit() == true) {
         return;
@@ -98,6 +196,9 @@ void CAudioInput::initialize() throw(CAudioError) {
 
     try {
         CAudioIO::initialize();
+        if (__IsPrivilegeAllowed() == false) {
+            THROW_ERROR_MSG(CAudioError::EError::ERROR_PERMISSION_DENIED, "No privilege for record");
+        }
 
         // Create ASM Handler
         mpAudioSessionHandler = new CAudioSessionHandler(CAudioSessionHandler::EAudioSessionType::AUDIO_SESSION_TYPE_CAPTURE, mAudioInfo, this);