1. 程式人生 > >讓linux支援qq手機音樂播放

讓linux支援qq手機音樂播放

Gmediarender 是一個模擬upnp renderlinux下的軟體,他可以接收qq音樂發來的資料並在電腦上播放出來。下面介紹一下方法:

網站http://gmrender.nongnu.org/下載gmediarender

  編譯,編譯過程回出現

gcc  -Wall -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -L/usr/lib  -o gmediarender  main.o upnp.o upnp_control.o upnp_connmgr.o upnp_transport.o upnp_device.o upnp_renderer.o webserver.o output_gstreamer.o xmlescape.o -pthread -lgstreamer-0.10 -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lxml2 -lglib-2.0   -lupnp 
/usr/bin/ld: upnp.o: undefined reference to symbol 'ixmlDocument_createElementNS'
//usr/lib/x86_64-linux-gnu/libixml.so.2: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
這樣的錯誤,grep上面的函式發現在下面檔案裡面:
/usr/lib/x86_64-linux-gnu/libixml.a
/usr/lib/x86_64-linux-gnu/libixml.so.2.0.7
解決方法,直接連結靜態庫:
gcc  -Wall -Wpointer-arith -Wcast-align -Wmissing-prototypes -Wmissing-declarations -L/usr/lib  -o gmediarender  main.o upnp.o upnp_control.o upnp_connmgr.o upnp_transport.o upnp_device.o upnp_renderer.o webserver.o output_gstreamer.o xmlescape.o -pthread -lgstreamer-0.10 -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lxml2 -lglib-2.0   -lupnp  /usr/lib/x86_64-linux-gnu/libixml.a
安裝完成後即可用手機qq音樂連線測試。

首先要保證電腦和手機連線到同一個網段(同一個wifi ap),在pc端執行gmediarender,然後開啟qq音樂後開始播放音樂,在播放介面出現一個圈圈帶箭頭圖示,點選該圖示顯示出新的播放裝置gmediarender,點選後音樂就傳送到了pc上,pc電腦就可以出聲音了。

Gmediarender 僅支援gst,我對其做了mpd的簡單擴充套件,讓聲音可以從mpd裡面播放出來,下面是擴充套件mpd支援的程式碼(非常初級,僅僅可以讓mpd播放聲音而已):

output_mpd.c

#ifdef HAVE_CONFIG_H

#include "config.h"

#endif

#include <mpd/client.h>

#include <mpd/status.h>

#include <mpd/song.h>

#include <mpd/entity.h>

#include <mpd/search.h>

#include <mpd/tag.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <glib.h>

//#define ENABLE_TRACING

#include "logging.h"

#include "upnp_connmgr.h"

#include "output_mpd.h"

static char *gsuri = NULL;

static struct mpd_connection *conn = NULL;

#define SET_CONN() conn = mpd_connection_new(NULL, 0, 30000)

#define FREE_CONN() mpd_connection_free(conn); conn=NULL

struct mpd_status *

getStatus(struct mpd_connection *conn)

{

struct mpd_status *ret = mpd_run_status(conn);

return ret;

}

static unsigned

query_queue_length(struct mpd_connection *conn)

{

struct mpd_status *status = getStatus(conn);

const unsigned length = mpd_status_get_queue_length(status);

mpd_status_free(status);

return length;

}

void output_set_uri(const char *uri)

{

ENTER();

printf("%s: setting uri to '%s'\n", __FUNCTION__, uri);

if (gsuri != NULL)

{

free(gsuri);

}

gsuri = strdup(uri);

LEAVE();

}

int output_play(void)

{

int result = -1;

int try_num=10;

enum mpd_server_error serror_error;

ENTER();

if(strlen(gsuri)==0)

{printf("usri is empty:%s\n");return -1;};

SET_CONN();

//next schedule it to the next play

printf("conn=%x\n",(unsigned int )conn);

struct mpd_status *status = getStatus(conn);

if(status==NULL)

{

if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {

printf("connection error code:%d,free connection\n", mpd_connection_get_error(conn));

serror_error=mpd_connection_get_server_error(conn);

printf("serror=%d\n",serror_error);

mpd_connection_free(conn);

}

}

const int playlist_len=mpd_status_get_queue_length(status);

printf("---playlist_len=%d,add song:%s\n",playlist_len,gsuri);

mpd_command_list_begin(conn, false);

if(playlist_len)

{

const int next_song_pos=mpd_status_get_next_song_pos(status);

printf("next_song_pos=%d\n",next_song_pos);

if(next_song_pos==-1)

{

mpd_send_add(conn,gsuri);

}

else

mpd_send_add_id_to(conn, gsuri,next_song_pos);

}

else{

mpd_send_add(conn,gsuri);

}

mpd_command_list_end(conn);

mpd_response_finish(conn);

mpd_run_play(conn); 

if(playlist_len)

mpd_run_next(conn);

   mpd_status_free(status);

   FREE_CONN();

result = 0;

LEAVE();

return result;

}

int output_stop(void)

{

SET_CONN();

mpd_run_stop(conn);

FREE_CONN();

return 0;

}

int output_pause(void)

{

SET_CONN();

mpd_run_pause(conn,true);

FREE_CONN();

  return 0;

}

int output_loop()

{

GMainLoop *loop;

/* Create a main loop that runs the default GLib main context */

loop = g_main_loop_new(NULL, FALSE);

g_main_loop_run(loop);

return 0;

}

int output_mpt_init(void)

{

ENTER();

SET_CONN();

if (conn == NULL) {

printf("%s", "Out of memory");

return -1;

}

if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS) {

printf("%s", mpd_connection_get_error_message(conn));

mpd_connection_free(conn);

conn = NULL;

return -1;

}

FREE_CONN();

LEAVE();

return 0;

}

output_mpd.h

#ifndef _OUTPUT_MPD_H

#define _OUTPUT_GSTREAMER_H

int output_mpd_init(void);

void output_set_uri(const char *uri);

int output_play(void);

int output_stop(void);

int output_pause(void);

int output_loop(void);

#endif /*  _OUTPUT_MPD_H */

需要注意的是qq網路音樂是把mov的字尾改動為字尾為mqcc的形式(qq本地傳入的音樂),而mpd又是以後綴作為解碼的依據,這個可以修改檔案src/decoder/plugins/FfmpegDecoderPlugin.cxx,找到:ffmpeg_suffixes,增加:"wve", "mqcc",後重新編譯即可支援。