웹 애플리케이션의 기본 오디오 재생 및 레코더 컨트롤에 액세스

웹 애플리케이션의 기본 오디오 재생 및 레코더 컨트롤에 액세스

이 자습서는 재생, 일시 중지, 정지, 검색과 같은 기본(또는 표준) 오디오 플레이어 컨트롤 및 웹 애플리케이션의 녹음 수행, 일시 중지, 정지와 같은 오디오 녹음 컨트롤에 액세스하는 방법을 이해하는 데 도움이 됩니다. 플레이어 컨트롤용 애플리케이션의 사용자 인터페이스를 생성하고, 웹 오디오 플레이어를 구현하지 않고 기존 기본 미디어 플레이어를 사용하려는 경우 필요할 수 있습니다. 샘플 애플리케이션은 오디오 재생 및 오디오 녹음에 대해서만 구현됩니다.

요구를 충족하려면 기본 애플리케이션이 UI 없는 서비스 애플리케이션이며 백그라운드에서 실행되는 기본 애플리케이션이 있는 Tizen 하이브리드 애플리케이션을 생성해야 합니다. 사용자 인터페이스 디자인은 웹 애플리케이션에서 이루어집니다.

Tizen의 MessagePort 장치 API는 다른 애플리케이션과 통신하기 위한 기능을 제공하며 웹과 기본 애플리케이션 간에 통신하기 위한 애플리케이션에서 동일한 API가 사용됩니다.

1 오디오 재생 하이브리드 애플리케이션

1.1 웹 애플리케이션 구현

Init 함수에서 재생에 대한 UI 컨트롤 버튼을 바인딩하고 해당 함수 처리기를 중지합니다. 또한 페이지 초기화 자체에서 기본 서비스 애플리케이션을 실행하여 서비스 포트를 사용할 수 있고 웹 애플리케이션에서 수신 대기할 준비가 됩니다. 애플리케이션 API launch 메서드는 기본 서비스 애플리케이션을 실행하기 위해 호출됩니다.

//First launch the service
   LaunchNativeService();
// Handle the play button
	$("#btn-play").bind("vclick", function(){
		audioPlayPause();
		return false;
	});
 //  Handle the stop button
	$("#btn-stop").bind("vclick", function(){
		stopPlayback();
		return false;
	});

기본 서비스 애플리케이션 실행의 일환으로, 서비스 애플리케이션이 이미 실행 중이거나 실행되어야 하는 경우 아래와 같이 현재 실행 중인 애플리케이션 또는 애플리케이션 컨텍스트 목록을 확보해야 하는지 확인해야 합니다.

function LaunchNativeService() {
  try {
    tizen.application.getAppsContext(onGetAppsContextSuccess, onGetAppsContextError);
  } catch (exc) {
    console.log("Get AppContext Error");
   }
}

성공한 경우 onGetAppsContextSuccess 메서드에는 현재 실행 중인 애플리케이션의 컨텍스트 정보가 있으며 서비스 애플리케이션이 실행되 고 있지 않은 경우 기본 서비스가 시작됩니다.

function onGetAppsContextSuccess(contexts) {
	for (var i = 0; i < contexts.length; i++) {
	    var appInfo = tizen.application.getAppInfo(contexts[i].appId);
	    if(appInfo.id == gServiceAppId){
		console.log("Running Service App found");
		ServiceAppFound=true;
		break;
	     }
	}
	if (ServiceAppFound) {
	    console.log("Service App found and ready to serve");
	    // Now initialize the message ports
	    console.log("Initializing message ports");
	    initMessagePort();
	}else{
	    console.log("Service app not ready, will launch the service now");
	    launchServiceApp();
	}
}

서비스 애플리케이션이 실행된 경우 메시지 포트는 서비스 애플리케이션과 통신하기 위해 초기화됩니다.

function launchServiceApp() {
	function onSuccess() {
	    console.log("Service App launched successfully!");
	    // Now initialize the message ports
	    console.log("Initializing message ports");
	    initMessagePort();
	}
	try {
	    console.log("Launching [" + gServiceAppId + "]");
	    tizen.application.launch(gServiceAppId, onSuccess, onError);
	} catch (exc) {
	    alert("launch exc:" + exc.message);
	}
}

메시지 포트 초기화의 일환으로, 로컬 메시지 포트 개체 인스턴스를 만들고 기본 서비스 애플리케이션에서 수신하기 위해 콜백 함수 onReceive 를 등록합니다.

gLocalMessagePort = tizen.messageport.requestLocalMessagePort(gLocalMessagePortName);
		gLocalMessagePortWatchId = gLocalMessagePort.addMessagePortListener( function(data, remote) { onReceive(data, remote);});

기본 서비스 애플리케이션으로 메시지를 보내려면 RemoteMessagePort 인터페이스의 개체 인스턴스를 만들고 sendMessage 메서드를 사용하여 데이터를 전송해야 합니다.

gRemoteMessagePort = tizen.messageport.requestRemoteMessagePort(gServiceAppId, gServicePortName);

function sendCommand(command)
{
   gRemoteMessagePort.sendMessage([ { key:"command", value:command } ], gLocalMessagePort);
   console.log("Sending: " + command);
}

서비스 애플리케이션에서 메시지를 받으면 메시지 데이터는 key-value 쌍으로 검색되고 적절하게 처리됩니다. 이 경우 서비스에서 재생이 시작되거나 중지되면 콘솔에 로그온합니다. 받은 메시지가 종료되는 경우 메시지 포트 수신기를 제거합니다.

for(var i in data) {
   if(data[i].key == "server")
   message = data[i].value;
   }
   console.log("Received : " + message);
   if(message == "started"){
	console.log("Playback using native media player started");
   }else if(message == "stopped"){
        console.log("Playback stopped");
   }else if(message == "exit"){
	 if(gRemoteMessagePort)
	    gRemoteMessagePort = null;
	 if(gLocalMessagePort) {			   gLocalMessagePort.removeMessagePortListener(gLocalMessagePortWatchId);
			gLocalMessagePort = null;
  	}
  }

1.2 기본 서비스 구현

플레이어 클래스 Tizen::Media::Player 는 RTSP 또는 HTTP를 통해 로컬 스토리지 및 서버에서 오디오 및 비디오 콘텐츠를 재생하는 메서드를 제공 합니다. 재생, 일시 중지, 다시 시작, 중지, 볼륨 제어, 오디오 또는 비디오 콘텐츠 루프와 같은 일반 컨트롤 및 기타 여러 가지 타이밍 메서드가 지원됩니다. 샘플 애플리케이션은 재생, 일시 중지 및 정지와 같은 기본 컨트롤을 사용한 오디오 재생을 보여줍니다.

서비스 애플리케이션 초기화

NativePlayerService.cpp에서 서비스 앱이 초기화 상태에 있을 때 호출되는 함수이므로 OnAppInitializing 메서드에서 서비스 메시지 포트와 미디어 플레이어 서비스를 초기화합니다.

// Initialize ServerMessagePort
__pMessagePort = new (std::nothrow) ServiceMessagePort();
TryReturn(__pMessagePort != null, false, "[E_FAILURE] Failed to create __pMessagePort.");
AppLog("__pMessagePort is created.");

r = __pMessagePort->Construct(LOCAL_MESSAGE_PORT);
TryReturn(IsFailed(r) != true, r, "[%s] Failed to construct __pMessagePort",     GetErrorMessage(r));
AppLog("__pMessagePort is constructed.");

그러면 미디어 플레이어 개체가 생성 및 초기됩니다.

__pMediaPlayer = new (std::nothrow) MediaPlayerService();
TryReturn(__pMediaPlayer != null, false, "[E_FAILURE] Failed to create __pMediaPlayer.");
AppLog("__pMediaPlayer is created.");

// Initialize Media player
__pMediaPlayer->InitPlayer();

웹 애플리케이션에서 서비스 요청 처리

서비스 메시지 포트의 OnMessageReceivedN 메서드(ServiceMessagePort.cpp 파일 내)는 웹 애플리케이션에서 요청을 처리하고 기본 서비스 애플리케이션 내에서 전파합니다. 메서드는 (웹 애플리케이션의) 원격 메시지 포트 정보와 고유 키와 단일 값에 대한 각 키 맵이 포함되어 있는 IMap 인스턴스로 처리될 메시지를 받습니다. 마찬가지로 데이터는 HashMap 인스턴스로서 웹 애플리케이션으로 다시 전송됩니다.

Imap 웹 애플리케이션에서 요청 데이터를 검색하기 위한 개체 인스턴스

String *pData = static_cast(pMessage->GetValue(String(L"command")));

HashMap 웹 애플리케이션에 대한 key-value 쌍에 데이터를 전송할 개체 인스턴스

HashMap *pMap = new HashMap(SingleObjectDeleter);
pMap->Construct();

다음은 수신한 데이터 값을 검색하고 사용자 이벤트를 서비스 애플리케이션 자체로 전송하는 방법입니다.

if (pData->Equals(String(L"start")))
{
    App* pApp = App::GetInstance();
    pApp->SendUserEvent(PLAYER_START, null);
    pMap->Add(new String(L"server"), new String(L"started"));
}

미디어 재생 서비스 처리

서비스 애플리케이션은 OnUserEventReceivedN 메서드에서 특정 플레이어 요청에 대한 처리기를 정의합니다(사용자 이벤트가 SendUserEvent 메서드에 의해 전송되는 경우).
서비스는 메시지 포트 처리기에서 이벤트 형태로 요청을 받습니다. 다음은 샘플 애플리케이션에서 처리된 두 플레이어 요청입니다.

// Handle the media playback requests here
switch (requestId)
{
   case PLAYER_START:
 	AppLog("Player start request received");
	if (__pMediaPlayer != null)
	{
           AppLog("Invoking Mediaplayer start process now...");
	   __pMediaPlayer->PlayAudio();
	}
	break;

   case PLAYER_STOP:
	AppLog("Player start request received");
	if (__pMediaPlayer != null)
	{
           AppLog("Invoking Mediaplayer stop process now...");
	   __pMediaPlayer->StopAudio();
	}
	break;

   case PLAYER_EXIT :
	Terminate();
	break;
   default:
	break;
}

다음과 같이 오디오 시작 이벤트가 트리거되고 MediaPlayerService 개체의 PlayAudio 메서드를 호출하여 서비스 애플리케이션이 이벤트를 진행한다고 가정해 보겠습니다(실제 재생은 mediaPlayerService 인터페이스에서 처리됩니다).

__pMediaPlayer->PlayAudio();

PlayAudio 메서드는 다음과 같이 MediaPlayerService 클래스에 정의됩니다. 재생이 진행 중이고 이 함수에 대한 호출이 재생을 일시 중지하는 경우 이는 동일한 함수가 재생 및 일시 중지를 전환한다는 의미입니다.

result MediaPlayerService::PlayAudio(void)
{
    AppLog("Start play/pause function called");
    result r = E_SUCCESS;

   if (PlayerObj.GetState() == PLAYER_STATE_PLAYING)
   {
      // Pause the Playing
       r = PlayerObj.Pause();
       if (IsFailed(r))
       {
	  return r;
       }
      AppLog("Audio paused");
   }
   else if ((PlayerObj.GetState() == PLAYER_STATE_PAUSED)
         || (PlayerObj.GetState() ==  PLAYER_STATE_OPENED)
         || (PlayerObj.GetState() == PLAYER_STATE_ENDOFCLIP)
         || (PlayerObj.GetState() == PLAYER_STATE_STOPPED))
   {
       AppLog("Setting volume");
       PlayerObj.SetVolume(80);

       AppLog("Starting playback");
       r = PlayerObj.Play();
       if (IsFailed(r))
       {
         return r;
       }
    }
     return r;
 }

2 오디오 레코더 하이브리드 애플리케이션

2.1 웹 애플리케이션 구현

오디오 레코더 페이지는 녹음, 설정, 녹음 중지, 녹음된 클릭 재생에 대한 옵션을 제공합니다. 다음은 페이지 바닥글에서의 수행 방법입니다. 설정 옵션이 선택된 경우 코덱 및 녹음 품질을 선택하라는 컨텍스트 팝업 메시지가 표시됩니다. 아는 사용자 선택에 대한 메서드는 javascrip 코드에 제공되지만 서비스에 연결하기 위해 구현되지는 않습니다. 녹음 시작 또는 중지 옵션에 대해 수행했던 key-value 쌍 명령처럼 간단한 방법입니다.기본 서비스와 통신하기 위한 메시지 포트 구현은 오디오 재생에 대해 설명한 것과 같습니다.

2.2 기본 서비스 구현

레코더 서비스 초기화

In NativeRecordService.cpp 파일에서 오디오 레코더 서비스를 만들고 초기화합니다. 초기화의 일환으로, AudioRecorder() 개체가 생성됩니다.

// Create Audio Recorder object
	__pAudioRecorderSer = new (std::nothrow) AudioRecorderService();
	TryReturn(__pMediaPlayer != null, false, "[E_FAILURE] Failed to create __pMediaPlayer.");
	AppLog("__pAudioRecorder is created.");

	// Create and Initialize Audio Recorder
	__pAudioRecorderSer->InitRecorder();

레코더 서비스 요청 처리

다음은 오디오 녹음에 대한 논리를 구현하는 AudioServiceRecorder.cpp에서 정의된 함수입니다.

result AudioRecorderService::StartAudioRecording(void)
{
	result res = E_SUCCESS;
	AppLog("StartAudioRecording called");
	String RecordedFilePath = Tizen::App::App::GetInstance()->GetAppRootPath() + L"data/recordedfile.amr";
	RecorderState state = __pAudiorecord->GetState();

	res = __pAudiorecord->CreateAudioFile(RecordedFilePath, true);
	if (IsFailed(res))
	{
	   return res;
	}
	if ((RECORDER_STATE_INITIALIZED == state) || (RECORDER_STATE_OPENED == state) || \
		(RECORDER_STATE_PAUSED == state) || (RECORDER_STATE_CLOSED == state) ||	\
		(RECORDER_STATE_STOPPED == state))
	{
		res = __pAudiorecord->Record();
		if (IsFailed(res))
		{
		   return res;
		}
	}
	return res;
}

오디오 레코더 샘플 애플리케이션은 기본 녹음 코덱(amr) 및 품질을 사용합니다. 처리기를 추가하여 원하는 대로(물론 지원되는 코덱 목록에서) 특정 녹음 코덱과 품질을 사용할 수 있습니다.

오디오 재생 및 오디오 녹음을 위한 구현 세부 사항에 대한 샘플 애플리케이션을 참조하십시오.

다음 명령을 사용하여 샘플 애플리케이션(HybridAudioPlayer.wgt 파일)을 설치합니다.

  • sdb root on
  • sdb push HybridAudioPlayer.wgt /opt/home/root/
  • sdb shell
  • $ cd /opt/home/root/
  • $ wrt-installer -i HybridAudioPlayer.wgt

스크린샷:

 

라이센스:
애플리케이션에 사용된 이미지는 Creative Commons License Attribution-ShareAlike 2.0에 따라 사용이 허가되었습니다.

개발 환경:

Tizen SDK

버전: 2.2.0
빌드 id : 20130708-1957