1.项目简介:
本次项目要求实现的是将手机或者其他手持终端上的存储音视频等多媒体文件通过无线网络推送至linux主机,并在linux实现播放的功能。同时,在播放的基础上,实现了手机端能够控制主机端媒体的暂停、快进、调节音量的等功能。在完成项目的过程当中,应用了DLNA(数字生活网络联盟)工程的解决方案完成了整个程序的架构,使用了upnp协议(通用即插即用)以及socket接口完成网络数据的传输,所以花了一定的时间查找、翻译与DLNA相关的英文文档。同时整个应用程序使用C++语言编写,涉及到了面向对象编程、多态、封装以及类的定义、构造、析构、派生等等诸多知识。
2.DLNA简介:
DLNA的中文全称是数字生活联盟,旨在解决个人PC,消费电器,移动设备在内的无线网络和有线网络的互联互通,使得数字媒体和内容服务的无限制的共享和增长成为可能。DLNA并不是一项技术,而是一项解决方案,一种大家都可遵守的规范,使用的协议和技术大部分都是当前使用很广技术。
DLNA架构是个互联系统,在模型上类似于网络的四七分层,包括5个功能组件,网络互连(指定网络连接的标准,有有线的标准也也有无线的,类似于链路层),网络协议(基于ipv4协议族的,使用TCP和UDP传输数据都可以),设备的发现控制和管理(UPNP协议用于设备的发现和控制),媒体传输(使用的HTTP协议来传输媒体内容),媒体格式(媒体编码格式)。
DLNA将整个工程中的设备分为5类,第一类:媒体服务器,用于存储和输出多媒体文件;第二类:控制器,控制多媒体文件的播放、暂停等操作;第三类:媒体播放器,从服务器上获取媒体信息并进行播放显示;第四类:渲染器,通过配置后可以播放服务器上的媒体,并具有查找媒体的功能,如显示器,音响等;第五类:媒体打印机,即网络打印机看,与本项目无关。
本次项目中,DLNA媒体服务器和控制器均为手机上的音乐播放器,DLNA媒体播放器为linux主机中的MPlayer播放器,我们完成的是DLNA的渲染器,主要的功能是能够接收媒体服务器的媒体文件、控制器的控制命令,然后操作MPlayer播放器完成具体的播放控制。
3.UPNP简介:
UPnP全名是通用即插即用协议,主要是微软在推行的一个标准。简单的来说,UPnP 最大的愿景就是希望任何设备只要一接上网络,所有在网络上的设备马上就能知道有新设备加入,这些设备彼此之间能互相沟通,更能直接使用或控制它,一切都不需要设定。UPnP设备体系结构包含了服务(包含状态表、事件和控制服务器)、设备(电子设备)、控制点(发现和控制其他设备)。完整的UPnP由设备寻址、设备发现、设备描述、设备控制、事件通知和表达几部分构成。寻址:UPnP协议的基础是TCP/IP,这就决定了每一个UPnP必须分配一个IP地址。当一个UPnP设备或 控制点接入网络时, 它能通过DHCP从网络上获取一个IP 地址。发现:当UPnP设备或控制点获得IP 地址以后, 设备可以通过网络向控制点提供自己的相关信息;而 控制点可以从网络上获取自己感兴趣的设备的信息。描述:当设备和控制点取得联系后,描述可以供控制点获取设备及其服务的详细信息。这些信息以X ML 格式提供,并通过HTTP协议进行传送。控制:当控制点获取了设备的信息后,控制点可以对该设备进行控制。控制点通过向该设备某个服务的URL发送操作请求来控制该设备。请求和响应消息同样是XML格式的,通过HTTP协议进行传送。事件:当设备的服务状态发生变化时设备通过事件来通知控制点。数据格式同样是XML的。表达:UPnP规定设备制造商通过展示可以提供该设备内容和功能的相关描述信息,描述信息以HTML 格式发布。
本次项目要求实现的是将手机或者其他手持终端上的存储音视频等多媒体文件通过无线网络推送至linux主机,并在linux实现播放的功能。同时,在播放的基础上,实现了手机端能够控制主机端媒体的暂停、快进、调节音量的等功能。在完成项目的过程当中,应用了DLNA(数字生活网络联盟)工程的解决方案完成了整个程序的架构,使用了upnp协议(通用即插即用)以及socket接口完成网络数据的传输,所以花了一定的时间查找、翻译与DLNA相关的英文文档。同时整个应用程序使用C++语言编写,涉及到了面向对象编程、多态、封装以及类的定义、构造、析构、派生等等诸多知识。
2.DLNA简介:
DLNA的中文全称是数字生活联盟,旨在解决个人PC,消费电器,移动设备在内的无线网络和有线网络的互联互通,使得数字媒体和内容服务的无限制的共享和增长成为可能。DLNA并不是一项技术,而是一项解决方案,一种大家都可遵守的规范,使用的协议和技术大部分都是当前使用很广技术。
DLNA架构是个互联系统,在模型上类似于网络的四七分层,包括5个功能组件,网络互连(指定网络连接的标准,有有线的标准也也有无线的,类似于链路层),网络协议(基于ipv4协议族的,使用TCP和UDP传输数据都可以),设备的发现控制和管理(UPNP协议用于设备的发现和控制),媒体传输(使用的HTTP协议来传输媒体内容),媒体格式(媒体编码格式)。
DLNA将整个工程中的设备分为5类,第一类:媒体服务器,用于存储和输出多媒体文件;第二类:控制器,控制多媒体文件的播放、暂停等操作;第三类:媒体播放器,从服务器上获取媒体信息并进行播放显示;第四类:渲染器,通过配置后可以播放服务器上的媒体,并具有查找媒体的功能,如显示器,音响等;第五类:媒体打印机,即网络打印机看,与本项目无关。
本次项目中,DLNA媒体服务器和控制器均为手机上的音乐播放器,DLNA媒体播放器为linux主机中的MPlayer播放器,我们完成的是DLNA的渲染器,主要的功能是能够接收媒体服务器的媒体文件、控制器的控制命令,然后操作MPlayer播放器完成具体的播放控制。
3.UPNP简介:
UPnP全名是通用即插即用协议,主要是微软在推行的一个标准。简单的来说,UPnP 最大的愿景就是希望任何设备只要一接上网络,所有在网络上的设备马上就能知道有新设备加入,这些设备彼此之间能互相沟通,更能直接使用或控制它,一切都不需要设定。UPnP设备体系结构包含了服务(包含状态表、事件和控制服务器)、设备(电子设备)、控制点(发现和控制其他设备)。完整的UPnP由设备寻址、设备发现、设备描述、设备控制、事件通知和表达几部分构成。寻址:UPnP协议的基础是TCP/IP,这就决定了每一个UPnP必须分配一个IP地址。当一个UPnP设备或 控制点接入网络时, 它能通过DHCP从网络上获取一个IP 地址。发现:当UPnP设备或控制点获得IP 地址以后, 设备可以通过网络向控制点提供自己的相关信息;而 控制点可以从网络上获取自己感兴趣的设备的信息。描述:当设备和控制点取得联系后,描述可以供控制点获取设备及其服务的详细信息。这些信息以X ML 格式提供,并通过HTTP协议进行传送。控制:当控制点获取了设备的信息后,控制点可以对该设备进行控制。控制点通过向该设备某个服务的URL发送操作请求来控制该设备。请求和响应消息同样是XML格式的,通过HTTP协议进行传送。事件:当设备的服务状态发生变化时设备通过事件来通知控制点。数据格式同样是XML的。表达:UPnP规定设备制造商通过展示可以提供该设备内容和功能的相关描述信息,描述信息以HTML 格式发布。
4.项目成果:
此项目通过无线网络把手机和电脑连接起来后,可以将手机中的媒体内容投放到电脑 屏幕里。并且可以通过手机端的网易云音乐软件控制电脑端歌曲的播放,也可以通过 BubbleUpnp 软件控制电脑端 MP4 格式的视频播放。
5.主要代码部分
PltMediaRenderer.h
#ifndef _PLT_MEDIA_RENDERER_H_ #define _PLT_MEDIA_RENDERER_H_ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "PltDeviceHost.h" #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> extern int fifo_fd_to_mp; extern int g_fifo_fd_from_mp; extern int g_time; extern pthread_mutex_t g_mutex; extern char g_info[100]; /*---------------------------------------------------------------------- | PLT_MediaRendererDelegate +---------------------------------------------------------------------*/ class PLT_MediaRendererDelegate { public: virtual ~PLT_MediaRendererDelegate() {} // ConnectionManager virtual NPT_Result OnGetCurrentConnectionInfo(PLT_ActionReference& action) = 0; // AVTransport virtual NPT_Result OnNext(PLT_ActionReference& action) = 0; virtual NPT_Result OnPause(PLT_ActionReference& action) = 0; virtual NPT_Result OnPlay(PLT_ActionReference& action) = 0; virtual NPT_Result OnPrevious(PLT_ActionReference& action) = 0; virtual NPT_Result OnSeek(PLT_ActionReference& action) = 0; virtual NPT_Result OnStop(PLT_ActionReference& action) = 0; virtual NPT_Result OnSetAVTransportURI(PLT_ActionReference& action) = 0; virtual NPT_Result OnSetPlayMode(PLT_ActionReference& action) = 0; // RenderingControl virtual NPT_Result OnSetVolume(PLT_ActionReference& action) = 0; virtual NPT_Result OnSetVolumeDB(PLT_ActionReference& action) = 0; virtual NPT_Result OnGetVolumeDBRange(PLT_ActionReference& action) = 0; virtual NPT_Result OnSetMute(PLT_ActionReference& action) = 0; }; /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate +---------------------------------------------------------------------*/ class My_PLT_MediaRendererDelegate:public PLT_MediaRendererDelegate { public: friend class Thread1; //歌曲播放状态 NPT_Result seek_flag; NPT_Result play_flag; //歌曲路径写入文件描述符 NPT_Result fd0; NPT_Result fd; NPT_Result cur_vol; NPT_Result song_change; My_PLT_MediaRendererDelegate(); ~My_PLT_MediaRendererDelegate(); //自定义 int get_play_flag(){ return play_flag; } NPT_Result SndCmd(char *cmd,int len); // ConnectionManager virtual NPT_Result OnGetCurrentConnectionInfo(PLT_ActionReference& action); // AVTransport virtual NPT_Result OnNext(PLT_ActionReference& action); virtual NPT_Result OnPause(PLT_ActionReference& action); virtual NPT_Result OnPlay(PLT_ActionReference& action); virtual NPT_Result OnPrevious(PLT_ActionReference& action); virtual NPT_Result OnSeek(PLT_ActionReference& action); virtual NPT_Result OnStop(PLT_ActionReference& action); virtual NPT_Result OnSetAVTransportURI(PLT_ActionReference& action); virtual NPT_Result OnSetPlayMode(PLT_ActionReference& action); // RenderingControl virtual NPT_Result OnSetVolume(PLT_ActionReference& action); virtual NPT_Result OnSetVolumeDB(PLT_ActionReference& action); virtual NPT_Result OnGetVolumeDBRange(PLT_ActionReference& action); virtual NPT_Result OnSetMute(PLT_ActionReference& action); }; class ThreadSnd : public NPT_Thread { public: void Run(void); //void TSndCmd(My_PLT_MediaRendererDelegate &, char *, int); }; class ThreadRcv : public NPT_Thread { public: void Run(void); }; /*---------------------------------------------------------------------- | PLT_MediaRenderer +---------------------------------------------------------------------*/ class PLT_MediaRenderer : public PLT_DeviceHost { public: PLT_MediaRenderer(const char* friendly_name, bool show_ip = false, const char* uuid = NULL, unsigned int port = 0, bool port_rebind = false); // methods virtual void SetDelegate(PLT_MediaRendererDelegate* delegate) { m_Delegate = delegate; } // PLT_DeviceHost methods virtual NPT_Result SetupServices(); virtual NPT_Result OnAction(PLT_ActionReference& action, const PLT_HttpRequestContext& context); protected: virtual ~PLT_MediaRenderer(); // PLT_MediaRendererInterface methods // ConnectionManager virtual NPT_Result OnGetCurrentConnectionInfo(PLT_ActionReference& action); // AVTransport virtual NPT_Result OnNext(PLT_ActionReference& action); virtual NPT_Result OnPause(PLT_ActionReference& action); virtual NPT_Result OnPlay(PLT_ActionReference& action); virtual NPT_Result OnPrevious(PLT_ActionReference& action); virtual NPT_Result OnSeek(PLT_ActionReference& action); virtual NPT_Result OnStop(PLT_ActionReference& action); virtual NPT_Result OnSetAVTransportURI(PLT_ActionReference& action); virtual NPT_Result OnSetPlayMode(PLT_ActionReference& action); // RenderingControl virtual NPT_Result OnSetVolume(PLT_ActionReference& action); virtual NPT_Result OnSetVolumeDB(PLT_ActionReference &action); virtual NPT_Result OnGetVolumeDBRange(PLT_ActionReference &action); virtual NPT_Result OnSetMute(PLT_ActionReference& action); private: PLT_MediaRendererDelegate* m_Delegate; }; #endif /* _PLT_MEDIA_RENDERER_H_ */
PltMediaRenderer.cpp
/*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "Neptune.h" #include "PltMediaRenderer.h" #include "PltService.h" #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <string.h> int fifo_fd_to_mp; //控制Mplayer管道 int g_fifo_fd_from_mp ; //接受Mplayer信息管道 int g_time=0; //歌曲播放时间 int g_time_all=0; //歌曲长度 char g_info[100]; char g_info_all[100]; int song_len=1; //输出歌曲长度一次标志位 pthread_mutex_t g_mutex; My_PLT_MediaRendererDelegate *my_Delegate; NPT_SET_LOCAL_LOGGER("platinum.media.renderer") /*---------------------------------------------------------------------- | external references +---------------------------------------------------------------------*/ extern NPT_UInt8 RDR_ConnectionManagerSCPD[]; extern NPT_UInt8 RDR_AVTransportSCPD[]; extern NPT_UInt8 RDR_RenderingControlSCPD[]; /*---------------------------------------------------------------------- | PLT_MediaRenderer::PLT_MediaRenderer +---------------------------------------------------------------------*/ PLT_MediaRenderer::PLT_MediaRenderer(const char* friendly_name, bool show_ip /* = false */, const char* uuid /* = NULL */, unsigned int port /* = 0 */, bool port_rebind /* = false */) : PLT_DeviceHost("/", uuid, "urn:schemas-upnp-org:device:MediaRenderer:1", friendly_name, show_ip, port, port_rebind), m_Delegate(NULL) { m_ModelDescription = "Plutinosoft AV Media Renderer Device"; m_ModelName = "AV Renderer Device"; m_ModelURL = "http://www.plutinosoft.com/platinum"; m_DlnaDoc = "DMR-1.50"; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::~PLT_MediaRenderer +---------------------------------------------------------------------*/ PLT_MediaRenderer::~PLT_MediaRenderer() { } void TSndCmd(My_PLT_MediaRendererDelegate &x,char *cmd ,int len) { x.SndCmd(cmd,len); } void ThreadRcv::Run(void) { while(1) { usleep(500*1000); char buff[1024] = ""; char *p = NULL; int position_time=0; read(g_fifo_fd_from_mp,buff,sizeof(buff)); position_time = g_time; if((p = strstr(buff,"ANS_TIME_POSITION="))!=NULL) { sscanf(p,"ANS_TIME_POSITION=%d",&g_time); if(position_time != g_time) { pthread_mutex_lock(&g_mutex); sprintf(g_info,"%02d:%02d:%02d",g_time/60/60,g_time/60%60,g_time%60); pthread_mutex_unlock(&g_mutex); //printf("-%s--%s----------now song position --> %s\n",__FILE__,__FUNCTION__,g_info); } p = NULL; } if(((p = strstr(buff,"ANS_LENGTH="))!=NULL) && (song_len==1)) { //printf("------------------------------------------------recvMpl\n"); sscanf(p,"ANS_LENGTH=%d",&g_time_all); pthread_mutex_lock(&g_mutex); sprintf(g_info_all,"%02d:%02d:%02d",g_time_all/60/60,g_time_all/60%60,g_time_all%60); //printf("---------------now---song length-------------------> %s\n\t************************************\n",g_info_all); pthread_mutex_unlock(&g_mutex); song_len=0; } } } void ThreadSnd:: Run(void) { while(1) { if(song_len==1) { TSndCmd(*my_Delegate,"get_time_length\n",strlen("get_time_length\n")); } usleep(500*1000); if(my_Delegate->get_play_flag()==1) { TSndCmd(*my_Delegate,"get_time_pos\n",strlen("get_time_pos\n")); } } } /*---------------------------------------------------------------------- | PLT_MediaRenderer::SetupServices +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::SetupServices() { my_Delegate = new My_PLT_MediaRendererDelegate(); this->SetDelegate(my_Delegate); NPT_Thread *threadSnd = new ThreadSnd(); threadSnd->Start(); NPT_Thread *threadRcv = new ThreadRcv(); threadRcv->Start(); NPT_Reference<PLT_Service> service; { /* AVTransport */ service = new PLT_Service( this, "urn:schemas-upnp-org:service:AVTransport:1", "urn:upnp-org:serviceId:AVTransport", "AVTransport", "urn:schemas-upnp-org:metadata-1-0/AVT/"); NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_AVTransportSCPD)); NPT_CHECK_FATAL(AddService(service.AsPointer())); service->SetStateVariableRate("LastChange", NPT_TimeInterval(0.2f)); service->SetStateVariable("A_ARG_TYPE_InstanceID", "0"); // GetCurrentTransportActions service->SetStateVariable("CurrentTransportActions", "Play,Pause,Stop,Seek,Next,Previous"); // GetDeviceCapabilities service->SetStateVariable("PossiblePlaybackStorageMedia", "NONE,NETWORK,HDD,CD-DA,UNKNOWN"); service->SetStateVariable("PossibleRecordStorageMedia", "NOT_IMPLEMENTED"); service->SetStateVariable("PossibleRecordQualityModes", "NOT_IMPLEMENTED"); // GetMediaInfo service->SetStateVariable("NumberOfTracks", "0"); service->SetStateVariable("CurrentMediaDuration", "00:00:00"); service->SetStateVariable("AVTransportURI", ""); service->SetStateVariable("AVTransportURIMetadata", "");; service->SetStateVariable("NextAVTransportURI", "NOT_IMPLEMENTED"); service->SetStateVariable("NextAVTransportURIMetadata", "NOT_IMPLEMENTED"); service->SetStateVariable("PlaybackStorageMedium", "NONE"); service->SetStateVariable("RecordStorageMedium", "NOT_IMPLEMENTED"); service->SetStateVariable("RecordMediumWriteStatus", "NOT_IMPLEMENTED"); // GetPositionInfo service->SetStateVariable("CurrentTrack", "0"); service->SetStateVariable("CurrentTrackDuration", "00:00:00"); service->SetStateVariable("CurrentTrackMetadata", ""); service->SetStateVariable("CurrentTrackURI", ""); service->SetStateVariable("RelativeTimePosition", "00:00:00"); service->SetStateVariable("AbsoluteTimePosition", "00:00:00"); service->SetStateVariable("RelativeCounterPosition", "2147483647"); // means NOT_IMPLEMENTED service->SetStateVariable("AbsoluteCounterPosition", "2147483647"); // means NOT_IMPLEMENTED // disable indirect eventing for certain state variables PLT_StateVariable* var; var = service->FindStateVariable("RelativeTimePosition"); if (var) var->DisableIndirectEventing(); var = service->FindStateVariable("AbsoluteTimePosition"); if (var) var->DisableIndirectEventing(); var = service->FindStateVariable("RelativeCounterPosition"); if (var) var->DisableIndirectEventing(); var = service->FindStateVariable("AbsoluteCounterPosition"); if (var) var->DisableIndirectEventing(); // GetTransportInfo service->SetStateVariable("TransportState", "NO_MEDIA_PRESENT"); service->SetStateVariable("TransportStatus", "OK"); service->SetStateVariable("TransportPlaySpeed", "1"); // GetTransportSettings service->SetStateVariable("CurrentPlayMode", "NORMAL"); service->SetStateVariable("CurrentRecordQualityMode", "NOT_IMPLEMENTED"); service.Detach(); service = NULL; } { /* ConnectionManager */ service = new PLT_Service( this, "urn:schemas-upnp-org:service:ConnectionManager:1", "urn:upnp-org:serviceId:ConnectionManager", "ConnectionManager"); NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_ConnectionManagerSCPD)); NPT_CHECK_FATAL(AddService(service.AsPointer())); service->SetStateVariable("CurrentConnectionIDs", "0"); // put all supported mime types here instead service->SetStateVariable("SinkProtocolInfo", "http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_PRO,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_SP_G726,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_FULL,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_MED,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVMED_BASE,http-get:*:audio/L16;rate=44100;channels=1:DLNA.ORG_PN=LPCM,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO,http-get:*:audio/L16;rate=44100;channels=2:DLNA.ORG_PN=LPCM,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM,http-get:*:video/x-ms-asf:DLNA.ORG_PN=VC1_ASF_AP_L1_WMA,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMDRM_WMABASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_FULL,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAFULL,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMABASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPLL_BASE,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_NTSC_XAC3,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMDRM_WMVSPLL_BASE,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_BASE,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_ASP_L5_SO_G726,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_LRG,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL_XAC3,http-get:*:audio/x-ms-wma:DLNA.ORG_PN=WMAPRO,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG1,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN,http-get:*:video/x-ms-asf:DLNA.ORG_PN=MPEG4_P2_ASF_ASP_L4_SO_G726,http-get:*:audio/L16;rate=48000;channels=2:DLNA.ORG_PN=LPCM,http-get:*:audio/mpeg:DLNA.ORG_PN=MP3X,http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVSPML_MP3,http-get:*:video/x-ms-wmv:*"); service->SetStateVariable("SourceProtocolInfo", ""); service.Detach(); service = NULL; } { /* RenderingControl */ service = new PLT_Service( this, "urn:schemas-upnp-org:service:RenderingControl:1", "urn:upnp-org:serviceId:RenderingControl", "RenderingControl", "urn:schemas-upnp-org:metadata-1-0/RCS/"); NPT_CHECK_FATAL(service->SetSCPDXML((const char*) RDR_RenderingControlSCPD)); NPT_CHECK_FATAL(AddService(service.AsPointer())); service->SetStateVariableRate("LastChange", NPT_TimeInterval(0.2f)); service->SetStateVariable("Mute", "0"); service->SetStateVariableExtraAttribute("Mute", "Channel", "Master"); service->SetStateVariable("Volume", "100"); service->SetStateVariableExtraAttribute("Volume", "Channel", "Master"); service->SetStateVariable("VolumeDB", "0"); service->SetStateVariableExtraAttribute("VolumeDB", "Channel", "Master"); service->SetStateVariable("PresetNameList", "FactoryDefaults"); service.Detach(); service = NULL; } return NPT_SUCCESS; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnAction +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnAction(PLT_ActionReference& action, const PLT_HttpRequestContext& context) { NPT_COMPILER_UNUSED(context); PLT_Service *service = action->GetActionDesc().GetService(); /* parse the action name */ NPT_String name = action->GetActionDesc().GetName(); // since all actions take an instance ID and we only support 1 instance // verify that the Instance ID is 0 and return an error here now if not NPT_String serviceType = action->GetActionDesc().GetService()->GetServiceType(); if (serviceType.Compare("urn:schemas-upnp-org:service:AVTransport:1", true) == 0) { if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) { action->SetError(718, "Not valid InstanceID"); return NPT_FAILURE; } } serviceType = action->GetActionDesc().GetService()->GetServiceType(); if (serviceType.Compare("urn:schemas-upnp-org:service:RenderingControl:1", true) == 0) { if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) { action->SetError(702, "Not valid InstanceID"); return NPT_FAILURE; } } /* Is it a ConnectionManager Service Action ? */ if (name.Compare("GetCurrentConnectionInfo", true) == 0) { return OnGetCurrentConnectionInfo(action); } /* Is it a AVTransport Service Action ? */ if (name.Compare("Next", true) == 0) { return OnNext(action); } if (name.Compare("Pause", true) == 0) { return OnPause(action); } if (name.Compare("Play", true) == 0) { return OnPlay(action); } if (name.Compare("Previous", true) == 0) { return OnPrevious(action); } if (name.Compare("Seek", true) == 0) { return OnSeek(action); } if (name.Compare("Stop", true) == 0) { return OnStop(action); } if (name.Compare("SetAVTransportURI", true) == 0) { return OnSetAVTransportURI(action); } if (name.Compare("SetPlayMode", true) == 0) { return OnSetPlayMode(action); } /* Is it a RendererControl Service Action ? */ if (name.Compare("SetVolume", true) == 0) { return OnSetVolume(action); } //设置默认音量 反馈到手机 if (name.Compare("GetVolume", true) == 0) { char vol[10] = ""; sprintf(vol,"%d",my_Delegate->cur_vol); service->SetStateVariable("Volume", vol); } if (name.Compare("SetVolumeDB", true) == 0) { return OnSetVolumeDB(action); } if (name.Compare("GetVolumeDBRange", true) == 0) { return OnGetVolumeDBRange(action); } if (name.Compare("SetMute", true) == 0) { return OnSetMute(action); } //同步播放进度 if(my_Delegate->seek_flag == 1){ my_Delegate->seek_flag = 0; } else{ pthread_mutex_lock(&g_mutex); service->SetStateVariable("RelativeTimePosition",g_info); service->SetStateVariable("AbsoluteTimePosition",g_info); pthread_mutex_unlock(&g_mutex); } //if(g_time == g_time_all && g_time_all != 0){ //my_Delegate->OnNext(action); //} // other actions rely on state variables NPT_CHECK_LABEL_WARNING(action->SetArgumentsOutFromStateVariable(), failure); return NPT_SUCCESS; failure: action->SetError(401,"No Such Action."); return NPT_FAILURE; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnGetCurrentConnectionInfo +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnGetCurrentConnectionInfo(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnGetCurrentConnectionInfo(action); } if (NPT_FAILED(action->VerifyArgumentValue("ConnectionID", "0"))) { action->SetError(706,"No Such Connection."); return NPT_FAILURE; } if (NPT_FAILED(action->SetArgumentValue("RcsID", "0"))){ return NPT_FAILURE; } if (NPT_FAILED(action->SetArgumentValue("AVTransportID", "0"))) { return NPT_FAILURE; } if (NPT_FAILED(action->SetArgumentOutFromStateVariable("ProtocolInfo"))) { return NPT_FAILURE; } if (NPT_FAILED(action->SetArgumentValue("PeerConnectionManager", "/"))) { return NPT_FAILURE; } if (NPT_FAILED(action->SetArgumentValue("PeerConnectionID", "-1"))) { return NPT_FAILURE; } if (NPT_FAILED(action->SetArgumentValue("Direction", "Input"))) { return NPT_FAILURE; } if (NPT_FAILED(action->SetArgumentValue("Status", "Unknown"))) { return NPT_FAILURE; } return NPT_SUCCESS; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnNext +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnNext(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnNext(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnPause +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnPause(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnPause(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnPlay +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnPlay(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnPlay(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnPrevious +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnPrevious(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnPrevious(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnSeek +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnSeek(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnSeek(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnStop +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnStop(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnStop(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnSetAVTransportURI +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnSetAVTransportURI(PLT_ActionReference& action) { // default implementation is using state variable NPT_String uri; NPT_CHECK_WARNING(action->GetArgumentValue("CurrentURI", uri)); NPT_String metadata; NPT_CHECK_WARNING(action->GetArgumentValue("CurrentURIMetaData", metadata)); PLT_Service* serviceAVT; NPT_CHECK_WARNING(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", serviceAVT)); // update service state variables serviceAVT->SetStateVariable("AVTransportURI", uri); serviceAVT->SetStateVariable("AVTransportURIMetaData", metadata); if (m_Delegate) { return m_Delegate->OnSetAVTransportURI(action); } return NPT_SUCCESS; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnSetPlayMode +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnSetPlayMode(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnSetPlayMode(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnSetVolume +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnSetVolume(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnSetVolume(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnSetVolumeDB +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnSetVolumeDB(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnSetVolumeDB(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnGetVolumeDBRange +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnGetVolumeDBRange(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnGetVolumeDBRange(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | PLT_MediaRenderer::OnSetMute +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnSetMute(PLT_ActionReference& action) { if (m_Delegate) { return m_Delegate->OnSetMute(action); } return NPT_ERROR_NOT_IMPLEMENTED; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::My_PLT_MediaRendererDelegate +---------------------------------------------------------------------*/ My_PLT_MediaRendererDelegate::My_PLT_MediaRendererDelegate() { pthread_mutex_init(&g_mutex,NULL); fifo_fd_to_mp = open("./contrMpl",O_RDWR); cur_vol = 30; play_flag = 0; seek_flag = 0; song_change= 1; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::~My_PLT_MediaRendererDelegate +---------------------------------------------------------------------*/ My_PLT_MediaRendererDelegate::~My_PLT_MediaRendererDelegate() { pthread_mutex_destroy(&g_mutex); close(fifo_fd_to_mp); close(g_fifo_fd_from_mp); } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::SndCmd +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::SndCmd(char *cmd,int len) { pthread_mutex_lock(&g_mutex); write(fifo_fd_to_mp,cmd,len); pthread_mutex_unlock(&g_mutex); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnGetCurrentConnectionInfo +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnGetCurrentConnectionInfo(PLT_ActionReference& action) { return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnPlay +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnPlay(PLT_ActionReference& action) { play_flag = 1; char read_buf[1024] = ""; //PLT_Service *service = action->GetActionDesc().GetService(); if(song_change==1) { //获取歌曲名称 PLT_Service *service = action->GetActionDesc().GetService(); NPT_String uri; //读歌曲状态路径变量 service->GetStateVariableValue("AVTransportURI", uri); //歌曲路径写入、播放 sprintf(read_buf,"loadfile %s\n",(char*)uri); //printf("--->uri=%s\n",(char *)uri); SndCmd(read_buf,strlen(read_buf)); //printf("len=%d\n",len); action->GetActionDesc().GetService()->SetStateVariable("RelativeTimePosition","00:00:00"); action->GetActionDesc().GetService()->SetStateVariable("AbsoluteTimePosition","00:00:00"); //歌曲播放状态变化 song_change=0; //状态信息反馈 service->SetStateVariable("TransportState", "PLAYING"); service->SetStateVariable("TransportStatus", "OK"); //设置正常音量 bzero(read_buf,sizeof(read_buf)); sprintf(read_buf,"volume %d 1\n",my_Delegate->cur_vol); SndCmd(read_buf,strlen(read_buf)); //printf("--------------------------------------------this is onplay\n"); } else { SndCmd("pause\n",strlen("pause\n")); //usleep(1000); sprintf(read_buf,"volume %d 1\n",my_Delegate->cur_vol); SndCmd(read_buf,strlen(read_buf)); //printf("*****************************************this is open pause\n"); } //状态信息反馈 return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnNext +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnNext(PLT_ActionReference& action) { //song_len = 1; return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnPause +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnPause(PLT_ActionReference& action) { PLT_Service *service = action->GetActionDesc().GetService(); SndCmd("pause\n",strlen("pause\n")); //反馈信息 service->SetStateVariable("TransportState", "PAUSED_PLAYBACK"); service->SetStateVariable("TransportStatus", "OK"); play_flag=0; //printf("--------------------------------------------this is OnPause\n"); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnPrevious +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnPrevious(PLT_ActionReference& action) { return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnSeek +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnSeek(PLT_ActionReference& action) { int seek_time_h =0, seek_time_m = 0,seek_time_s = 0; int seek_pos = 0; seek_flag = 1; PLT_Service *service = action->GetActionDesc().GetService(); NPT_String seek; action->GetArgumentValue("Target",seek); sscanf((char *)seek,"%02d:%02d:%02d",&seek_time_h,&seek_time_m,&seek_time_s); seek_pos = (seek_time_h * 60 *60+seek_time_m *60+seek_time_s); int offset = seek_pos - g_time; char cmd[256]=""; service->SetStateVariable("RelativeTimePosition",(char *)seek); service->SetStateVariable("AbsoluteTimePosition",(char *)seek); sprintf(cmd,"seek %d\n",offset); SndCmd(cmd,strlen(cmd)); //usleep(300*1000); bzero(cmd,sizeof(cmd)); sprintf(cmd,"volume %d 1\n ",my_Delegate->cur_vol); SndCmd(cmd,strlen(cmd)); play_flag = 1; service->SetStateVariable("TransportState","PLAYING"); service->SetStateVariable("TransportStatus","OK"); //printf("--------------------------------------------this is OnSeek\n"); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnStop +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnStop(PLT_ActionReference& action) { PLT_Service *service = action->GetActionDesc().GetService(); SndCmd("pause\n",strlen("pause\n")); play_flag = 0; //反馈信息 service->SetStateVariable("TransportState", "STOPPED"); service->SetStateVariable("TransportStatus", "OK"); song_change = 1; //printf("--------------------------------------------this is OnStop\n"); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnSetAVTransportURI +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnSetAVTransportURI(PLT_ActionReference& action) { play_flag=1; song_change=1; return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnSetPlayMode +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnSetPlayMode(PLT_ActionReference& action) { return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnSetVolume +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnSetVolume(PLT_ActionReference& action) { NPT_String vol; action->GetArgumentValue("DesiredVolume",vol); //printf("----%s--%s------>volume=%s\n",__FILE__,__FUNCTION__,(char *)vol); sscanf((char*)vol,"%d",&(my_Delegate->cur_vol)); char cmd[128]=""; int len=sprintf(cmd,"volume %d 1\n",my_Delegate->cur_vol); SndCmd(cmd,len); if(play_flag == 0) SndCmd("pause\n",strlen("pause\n")); //usleep(1000*1000); return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnSetVolumeDB +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnSetVolumeDB(PLT_ActionReference& action) { return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnGetVolumeDBRange +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnGetVolumeDBRange(PLT_ActionReference& action) { return NPT_SUCCESS; } /*---------------------------------------------------------------------- | My_PLT_MediaRendererDelegate::OnSetMute +---------------------------------------------------------------------*/ NPT_Result My_PLT_MediaRendererDelegate::OnSetMute(PLT_ActionReference& action) { return NPT_SUCCESS; }
MediaRendererTest.cpp
/*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "PltUPnP.h" #include "PltMediaRenderer.h" #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /*---------------------------------------------------------------------- | globals +---------------------------------------------------------------------*/ struct Options { const char* friendly_name; } Options; /*---------------------------------------------------------------------- | PrintUsageAndExit +---------------------------------------------------------------------*/ static void PrintUsageAndExit(char** args) { fprintf(stderr, "usage: %s [-f <friendly_name>]\n", args[0]); fprintf(stderr, "-f : optional upnp server friendly name\n"); fprintf(stderr, "<path> : local path to serve\n"); exit(1); } /*---------------------------------------------------------------------- | ParseCommandLine +---------------------------------------------------------------------*/ static void ParseCommandLine(char** args) { const char* arg; char** tmp = args+1; /* default values */ Options.friendly_name = NULL; while ((arg = *tmp++)) { if (!strcmp(arg, "-f")) { Options.friendly_name = *tmp++; } else { fprintf(stderr, "ERROR: too many arguments\n"); PrintUsageAndExit(args); } } } /*---------------------------------------------------------------------- | main +---------------------------------------------------------------------*/ int main(int /* argc */, char** argv) { //创建命名管道 负责发送控制消息和读取返回信息 mkfifo("./contrMpl",0666); mkfifo("./readMpl",0666); g_fifo_fd_from_mp = open("./readMpl",O_RDWR); //创建子进程启动mplayer pid_t pid = fork(); if(pid < 0 ){ perror("fork"); exit(-1); } else if(pid == 0){ //重定向标准输出 dup2(g_fifo_fd_from_mp,1); execlp("mplayer","mplayer_arm", "-slave","-idle", "-quiet","-input","file=./contrMpl",NULL); perror("execl"); _exit(1); } PLT_UPnP upnp; /* parse command line */ ParseCommandLine(argv); PLT_DeviceHostReference device( new PLT_MediaRenderer(Options.friendly_name?Options.friendly_name:"Platinum Media Renderer", false, "e6572b54-f3c7-2d91-2fb5-b757f2537e21")); upnp.AddDevice(device); bool added = true; upnp.Start(); char buf[256]; while (gets(buf)) { if (*buf == 'q') break; if (*buf == 's') { if (added) { upnp.RemoveDevice(device); } else { upnp.AddDevice(device); } added = !added; } } upnp.Stop(); return 0; }