在 Web 应用程序中访问本机音频播放和录制器控件

在 Web 应用程序中访问本机音频播放和录制器控件

本教程可以帮助了解如何在 web 应用程序中访问本机 (或标准) 音频播放器控件(如播放、 暂停、 停止、 寻址)和音频录制控件 (如录制、 暂停和停止录制)。 当您想要在您的应用程序中为播放器控件创建自己的用户界面,并且想要使用现有的本机媒体播放器而不是实施 web 音频播放器,您可能需要本教程。 示例应用程序仅为音频播放和音频录制而执行。

为了满足我们的需求,我们需要创建一个 Tizen 混合应用程序项目,在该项目中,本机应用程序将是一个服务应用程序(没有 UI),并将在后台运行。 用户界面设计在 web 应用程序中完成。

Tizen MessagePort 设备的 API 提供与其他应用程序进行通信的功能,我们的应用程序使用相同的 API,用于 web 和本机应用程序之间的通信。

1 音频播放混合应用程序

1.1 Web 应用程序的实施

init 函数中,我们用各自的函数处理程序绑定播放和停止的 UI 控件按钮。 我们还在页面初始化中启动本机服务应用程序,以便您有可用的服务端口,并准备好从 web 应用程序侦听。 应用程序 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);
}

在从服务应用程序接收消息时,消息数据会被恢复为键值对,并进行相应处理。 在我们的例子中,我们只是登录到控制台,如果播放已从服务启动或停止。 如果接收到的消息是退出,则我们只需删除消息端口侦听器。

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();

处理来自 web 应用程序的服务请求

服务消息端口的 OnMessageReceivedN 方法(在文件 ServiceMessagePort.cpp 中) 负责处理来自 web 应用程序的请求并将它传送到本机服务应用程序中。 方法接收(web 应用程序的)远程消息端口的信息和作为实例处理的消息 IMap 该消息包含唯一键,每个键映射到一个单一的值。 同样地,数据作为实例被发送回 web 应用程序 HashMap

Imap 要从 web 应用程序检索请求数据的对象实例

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

HashMap 将键值对中的数据发送到 web 应用程序的对象实例

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 Web 应用程序的实施

音频录制器页面提供用于录制、 设置、 停止录制和播放录制片段的选项。 在页脚中会演示如何实现这些功能。 选择设置选项后,将弹出一个对话框,提示您选择编解码器和录制质量。 javascript 代码中会提供了解用户选择的方法,但不会实施这些方法来与服务通信。 做法很简单,就像我们执行开始或停止录制选项的键值对命令一样。消息端口与本机服务实现通信的方法与音频播放功能实现通信的方法相同。

2.2 本机服务实现

初始化录制器服务

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

屏幕快照:

 

许可证:
在应用程序中使用的图像均根据知识共享署名 2.0 许可授权。

开发环境:

Tizen SDK

版本: 2.2.0
构建 id: 20130708-1957