mirror of
https://github.com/albfan/miraclecast.git
synced 2025-02-14 18:41:54 +00:00
Merge branch 'agusakov'
This commit is contained in:
commit
640f731d44
18 changed files with 562 additions and 44 deletions
|
@ -4,12 +4,15 @@ DEBUG='0'
|
|||
AUDIO='0'
|
||||
SCALE='0'
|
||||
|
||||
while getopts "d:as:" optname
|
||||
while getopts "r:d:as:" optname
|
||||
do
|
||||
case "$optname" in
|
||||
"d")
|
||||
DEBUG=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"r")
|
||||
RESOLUTION=`echo ${OPTARG} | tr -d ' '`
|
||||
;;
|
||||
"a")
|
||||
AUDIO='1'
|
||||
;;
|
||||
|
|
|
@ -19,6 +19,7 @@ miracle_sinkctl_SOURCES = \
|
|||
ctl-cli.c \
|
||||
ctl-sink.c \
|
||||
ctl-wifi.c \
|
||||
wfd.c \
|
||||
sinkctl.c
|
||||
miracle_sinkctl_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS) \
|
||||
|
|
|
@ -97,11 +97,10 @@ int cli_help(const struct cli_cmd *cmds)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
if (is_cli()) {
|
||||
cli_printf("Available commands:\n");
|
||||
} else {
|
||||
if (!is_cli()) {
|
||||
cli_fn_help();
|
||||
}
|
||||
cli_printf("Available commands:\n");
|
||||
|
||||
for (i = 0; cmds[i].cmd; ++i) {
|
||||
if (!cmds[i].desc)
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "rtsp.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_util.h"
|
||||
#include "wfd.h"
|
||||
|
||||
struct ctl_sink {
|
||||
sd_event *event;
|
||||
|
@ -51,6 +52,13 @@ struct ctl_sink {
|
|||
|
||||
bool connected : 1;
|
||||
bool hup : 1;
|
||||
|
||||
uint32_t resolutions_cea;
|
||||
uint32_t resolutions_vesa;
|
||||
uint32_t resolutions_hh;
|
||||
|
||||
int hres;
|
||||
int vres;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -120,13 +128,37 @@ static void sink_handle_get_parameter(struct ctl_sink *s,
|
|||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
|
||||
r = rtsp_message_append(rep, "{&&&&}",
|
||||
"wfd_content_protection: none",
|
||||
"wfd_video_formats: 00 00 01 01 0000007f 003fffff 00000000 00 0000 0000 00 none none",
|
||||
"wfd_audio_codecs: AAC 00000007 00",
|
||||
"wfd_client_rtp_ports: RTP/AVP/UDP;unicast 1991 0 mode=play");
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
/* wfd_content_protection */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_content_protection") >= 0) {
|
||||
r = rtsp_message_append(rep, "{&}",
|
||||
"wfd_content_protection: none");
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
/* wfd_video_formats */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_video_formats") >= 0) {
|
||||
char wfd_video_formats[128];
|
||||
sprintf(wfd_video_formats,
|
||||
"wfd_video_formats: 00 00 03 10 %08x %08x %08x 00 0000 0000 10 none none",
|
||||
s->resolutions_cea, s->resolutions_vesa, s->resolutions_hh);
|
||||
r = rtsp_message_append(rep, "{&}", wfd_video_formats);
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
/* wfd_audio_codecs */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_audio_codecs") >= 0) {
|
||||
r = rtsp_message_append(rep, "{&}",
|
||||
"wfd_audio_codecs: AAC 00000007 00");
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
/* wfd_client_rtp_ports */
|
||||
if (rtsp_message_read(m, "{<>}", "wfd_client_rtp_ports") >= 0) {
|
||||
r = rtsp_message_append(rep, "{&}",
|
||||
"wfd_client_rtp_ports: RTP/AVP/UDP;unicast 1991 0 mode=play");
|
||||
if (r < 0)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
|
||||
rtsp_message_seal(rep);
|
||||
cli_debug("OUTGOING: %s\n", rtsp_message_get_raw(rep));
|
||||
|
@ -182,6 +214,27 @@ static int sink_setup_fn(struct rtsp *bus, struct rtsp_message *m, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int sink_set_format(struct ctl_sink *s,
|
||||
unsigned int cea_res,
|
||||
unsigned int vesa_res,
|
||||
unsigned int hh_res)
|
||||
{
|
||||
int hres, vres;
|
||||
|
||||
if ((vfd_get_cea_resolution(cea_res, &hres, &vres) == 0) ||
|
||||
(vfd_get_vesa_resolution(vesa_res, &hres, &vres) == 0) ||
|
||||
(vfd_get_hh_resolution(hh_res, &hres, &vres) == 0)) {
|
||||
if (hres && vres) {
|
||||
s->hres = hres;
|
||||
s->vres = vres;
|
||||
ctl_fn_sink_resolution_set(s, hres, vres);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void sink_handle_set_parameter(struct ctl_sink *s,
|
||||
struct rtsp_message *m)
|
||||
{
|
||||
|
@ -189,6 +242,7 @@ static void sink_handle_set_parameter(struct ctl_sink *s,
|
|||
const char *trigger;
|
||||
const char *url;
|
||||
char *nu;
|
||||
unsigned int cea_res, vesa_res, hh_res;
|
||||
int r;
|
||||
|
||||
r = rtsp_message_new_reply_for(m, &rep, RTSP_CODE_OK, NULL);
|
||||
|
@ -219,16 +273,19 @@ static void sink_handle_set_parameter(struct ctl_sink *s,
|
|||
}
|
||||
}
|
||||
|
||||
rtsp_message_exit_header(m);
|
||||
rtsp_message_exit_body(m);
|
||||
/* M4 again */
|
||||
r = rtsp_message_read(m, "{<****hhh>}", "wfd_video_formats",
|
||||
&cea_res, &vesa_res, &hh_res);
|
||||
if (r == 0) {
|
||||
r = sink_set_format(s, cea_res, vesa_res, hh_res);
|
||||
if (r)
|
||||
return cli_vERR(r);
|
||||
}
|
||||
|
||||
/* M5 */
|
||||
r = rtsp_message_read(m, "{<s>}", "wfd_trigger_method", &trigger);
|
||||
if (r < 0) {
|
||||
rtsp_message_exit_header(m);
|
||||
rtsp_message_exit_body(m);
|
||||
if (r < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(trigger, "SETUP")) {
|
||||
if (!s->url) {
|
||||
|
@ -453,6 +510,9 @@ int ctl_sink_new(struct ctl_sink **out,
|
|||
|
||||
s->event = sd_event_ref(event);
|
||||
s->fd = -1;
|
||||
s->resolutions_cea = wfd_supported_res_cea;
|
||||
s->resolutions_vesa = wfd_supported_res_vesa;
|
||||
s->resolutions_hh = wfd_supported_res_hh;
|
||||
|
||||
*out = s;
|
||||
return 0;
|
||||
|
|
|
@ -975,6 +975,17 @@ static int ctl_wifi_peer_fn(sd_bus *bus,
|
|||
return cli_log_parser(r);
|
||||
|
||||
ctl_fn_peer_provision_discovery(p, prov, pin);
|
||||
} else if (sd_bus_message_is_signal(m,
|
||||
"org.freedesktop.miracle.wifi.Peer",
|
||||
"GoNegRequest")) {
|
||||
/* connection request */
|
||||
const char *prov, *pin;
|
||||
|
||||
r = sd_bus_message_read(m, "ss", &prov, &pin);
|
||||
if (r < 0)
|
||||
return cli_log_parser(r);
|
||||
|
||||
ctl_fn_peer_go_neg_request(p, prov, pin);
|
||||
} else if (sd_bus_message_is_signal(m,
|
||||
"org.freedesktop.miracle.wifi.Peer",
|
||||
"FormationFailure")) {
|
||||
|
|
|
@ -236,6 +236,10 @@ struct cli_cmd {
|
|||
extern sd_event *cli_event;
|
||||
extern sd_bus *cli_bus;
|
||||
|
||||
extern unsigned int wfd_supported_res_cea;
|
||||
extern unsigned int wfd_supported_res_vesa;
|
||||
extern unsigned int wfd_supported_res_hh;
|
||||
|
||||
int cli_init(sd_bus *bus, const struct cli_cmd *cmds);
|
||||
void cli_destroy(void);
|
||||
int cli_run(void);
|
||||
|
@ -252,6 +256,9 @@ void ctl_fn_peer_free(struct ctl_peer *p);
|
|||
void ctl_fn_peer_provision_discovery(struct ctl_peer *p,
|
||||
const char *prov,
|
||||
const char *pin);
|
||||
void ctl_fn_peer_go_neg_request(struct ctl_peer *p,
|
||||
const char *prov,
|
||||
const char *pin);
|
||||
void ctl_fn_peer_formation_failure(struct ctl_peer *p, const char *reason);
|
||||
void ctl_fn_peer_connected(struct ctl_peer *p);
|
||||
void ctl_fn_peer_disconnected(struct ctl_peer *p);
|
||||
|
@ -260,6 +267,7 @@ void ctl_fn_link_free(struct ctl_link *l);
|
|||
|
||||
void ctl_fn_sink_connected(struct ctl_sink *s);
|
||||
void ctl_fn_sink_disconnected(struct ctl_sink *s);
|
||||
void ctl_fn_sink_resolution_set(struct ctl_sink *s, int hres, int vres);
|
||||
|
||||
void cli_fn_help(void);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "ctl.h"
|
||||
#include "wfd.h"
|
||||
#include "shl_macro.h"
|
||||
#include "shl_util.h"
|
||||
|
||||
|
@ -49,9 +50,13 @@ static pid_t sink_pid;
|
|||
static char *bound_link;
|
||||
static struct ctl_link *running_link;
|
||||
static struct ctl_peer *running_peer;
|
||||
static struct ctl_peer *pending_peer;
|
||||
|
||||
char *gst_scale_res;
|
||||
int gst_audio_en = 1;
|
||||
unsigned int wfd_supported_res_cea = 0x0000001f; /* up to 720x576 */
|
||||
unsigned int wfd_supported_res_vesa = 0x00000003; /* up to 800x600 */
|
||||
unsigned int wfd_supported_res_hh = 0x00000000; /* not supported */
|
||||
|
||||
/*
|
||||
* cmd list
|
||||
|
@ -280,6 +285,14 @@ static int scan_timeout_fn(sd_event_source *s, uint64_t usec, void *data)
|
|||
{
|
||||
stop_timeout(&scan_timeout);
|
||||
|
||||
if (pending_peer) {
|
||||
if (cli_running()) {
|
||||
cli_printf("[" CLI_RED "TIMEOUT" CLI_DEFAULT "] waiting for %s\n",
|
||||
pending_peer->friendly_name);
|
||||
}
|
||||
pending_peer = NULL;
|
||||
}
|
||||
|
||||
if (running_link)
|
||||
ctl_link_set_p2p_scanning(running_link, true);
|
||||
|
||||
|
@ -321,9 +334,10 @@ static const struct cli_cmd cli_cmds[] = {
|
|||
{ },
|
||||
};
|
||||
|
||||
static void spawn_gst(void)
|
||||
static void spawn_gst(int hres, int vres)
|
||||
{
|
||||
char *argv[64];
|
||||
char resolution[64];
|
||||
pid_t pid;
|
||||
int fd_journal, i;
|
||||
sigset_t mask;
|
||||
|
@ -363,6 +377,11 @@ static void spawn_gst(void)
|
|||
argv[i++] = "-s";
|
||||
argv[i++] = gst_scale_res;
|
||||
}
|
||||
if (hres && vres) {
|
||||
sprintf(resolution, "%dx%d", hres, vres);
|
||||
argv[i++] = "-r";
|
||||
argv[i++] = resolution;
|
||||
}
|
||||
argv[i] = NULL;
|
||||
|
||||
execve(argv[0], argv, environ);
|
||||
|
@ -385,7 +404,6 @@ void ctl_fn_sink_connected(struct ctl_sink *s)
|
|||
{
|
||||
cli_notice("SINK connected");
|
||||
sink_connected = true;
|
||||
spawn_gst();
|
||||
}
|
||||
|
||||
void ctl_fn_sink_disconnected(struct ctl_sink *s)
|
||||
|
@ -399,6 +417,13 @@ void ctl_fn_sink_disconnected(struct ctl_sink *s)
|
|||
}
|
||||
}
|
||||
|
||||
void ctl_fn_sink_resolution_set(struct ctl_sink *s, int hres, int vres)
|
||||
{
|
||||
cli_printf("SINK set resolution %dx%d\n", hres, vres);
|
||||
if (sink_connected)
|
||||
spawn_gst(hres, vres);
|
||||
}
|
||||
|
||||
void ctl_fn_peer_new(struct ctl_peer *p)
|
||||
{
|
||||
if (p->l != running_link || shl_isempty(p->wfd_subelements))
|
||||
|
@ -414,6 +439,14 @@ void ctl_fn_peer_free(struct ctl_peer *p)
|
|||
if (p->l != running_link || shl_isempty(p->wfd_subelements))
|
||||
return;
|
||||
|
||||
if (p == pending_peer) {
|
||||
cli_printf("no longer waiting for peer %s (%s)\n",
|
||||
p->friendly_name, p->label);
|
||||
pending_peer = NULL;
|
||||
stop_timeout(&scan_timeout);
|
||||
ctl_link_set_p2p_scanning(p->l, true);
|
||||
}
|
||||
|
||||
if (p == running_peer) {
|
||||
cli_printf("no longer running on peer %s\n",
|
||||
running_peer->label);
|
||||
|
@ -440,10 +473,23 @@ void ctl_fn_peer_provision_discovery(struct ctl_peer *p,
|
|||
if (cli_running())
|
||||
cli_printf("[" CLI_YELLOW "PROV" CLI_DEFAULT "] Peer: %s Type: %s PIN: %s\n",
|
||||
p->label, prov, pin);
|
||||
}
|
||||
|
||||
void ctl_fn_peer_go_neg_request(struct ctl_peer *p,
|
||||
const char *prov,
|
||||
const char *pin)
|
||||
{
|
||||
if (p->l != running_link || shl_isempty(p->wfd_subelements))
|
||||
return;
|
||||
|
||||
if (cli_running())
|
||||
cli_printf("[" CLI_YELLOW "GO NEG" CLI_DEFAULT "] Peer: %s Type: %s PIN: %s\n",
|
||||
p->label, prov, pin);
|
||||
|
||||
if (!running_peer) {
|
||||
/* auto accept any incoming connection attempt */
|
||||
ctl_peer_connect(p, "auto", "");
|
||||
pending_peer = p;
|
||||
|
||||
/* 60s timeout in case the connect fails. Yes, stupid wpas does
|
||||
* not catch this and notify us.. and as it turns out, DHCP
|
||||
|
@ -480,6 +526,8 @@ void ctl_fn_peer_connected(struct ctl_peer *p)
|
|||
cli_printf("[" CLI_GREEN "CONNECT" CLI_DEFAULT "] Peer: %s\n",
|
||||
p->label);
|
||||
|
||||
pending_peer = NULL;
|
||||
|
||||
if (!running_peer) {
|
||||
running_peer = p;
|
||||
cli_printf("now running on peer %s\n", running_peer->label);
|
||||
|
@ -557,9 +605,15 @@ void cli_fn_help()
|
|||
" --log-level <lvl> Maximum level for log messages\n"
|
||||
" --audio <0/1> Enable audio support (default %d)\n"
|
||||
" --scale WxH Scale to resolution\n"
|
||||
" --res <n,n,n> Supported resolutions masks (CEA, VESA, HH)\n"
|
||||
" default CEA %08X\n"
|
||||
" default VESA %08X\n"
|
||||
" default HH %08X\n"
|
||||
"\n"
|
||||
"Commands:\n"
|
||||
, program_invocation_short_name, gst_audio_en);
|
||||
, program_invocation_short_name, gst_audio_en,
|
||||
wfd_supported_res_cea, wfd_supported_res_vesa, wfd_supported_res_hh
|
||||
);
|
||||
wfd_print_resolutions();
|
||||
/*
|
||||
* 80-char barrier:
|
||||
* 01234567890123456789012345678901234567890123456789012345678901234567890123456789
|
||||
|
@ -627,6 +681,7 @@ static int parse_argv(int argc, char *argv[])
|
|||
ARG_LOG_LEVEL,
|
||||
ARG_AUDIO,
|
||||
ARG_SCALE,
|
||||
ARG_RES,
|
||||
};
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
|
@ -634,6 +689,7 @@ static int parse_argv(int argc, char *argv[])
|
|||
{ "log-level", required_argument, NULL, ARG_LOG_LEVEL },
|
||||
{ "audio", required_argument, NULL, ARG_AUDIO },
|
||||
{ "scale", required_argument, NULL, ARG_SCALE },
|
||||
{ "res", required_argument, NULL, ARG_RES },
|
||||
{}
|
||||
};
|
||||
int c;
|
||||
|
@ -654,6 +710,12 @@ static int parse_argv(int argc, char *argv[])
|
|||
case ARG_SCALE:
|
||||
gst_scale_res = optarg;
|
||||
break;
|
||||
case ARG_RES:
|
||||
sscanf(optarg, "%x,%x,%x",
|
||||
&wfd_supported_res_cea,
|
||||
&wfd_supported_res_vesa,
|
||||
&wfd_supported_res_hh);
|
||||
break;
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
220
src/ctl/wfd.c
Normal file
220
src/ctl/wfd.c
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2014 Andrey Gusakov <andrey.gusakov@cogentembedded.com>
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* MiracleCast is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MiracleCast is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "ctl.h"
|
||||
|
||||
struct resolution_bitmap {
|
||||
int index;
|
||||
int hres;
|
||||
int vres;
|
||||
int fps;
|
||||
};
|
||||
|
||||
/*
|
||||
* CEA resolutions and refrash rate bitmap/index table
|
||||
* also used in native resolution field
|
||||
*/
|
||||
struct resolution_bitmap resolutions_cea[] = {
|
||||
{0, 640, 480, 60}, /* p60 */
|
||||
{1, 720, 480, 60}, /* p60 */
|
||||
{2, 720, 480, 60}, /* i60 */
|
||||
{3, 720, 576, 50}, /* p50 */
|
||||
{4, 720, 576, 50}, /* i50 */
|
||||
{5, 1280, 720, 30}, /* p30 */
|
||||
{6, 1280, 720, 60}, /* p60 */
|
||||
{7, 1920, 1080, 30}, /* p30 */
|
||||
{8, 1920, 1080, 60}, /* p60 */
|
||||
{9, 1920, 1080, 60}, /* i60 */
|
||||
{10, 1280, 720, 25}, /* p25 */
|
||||
{11, 1280, 720, 50}, /* p50 */
|
||||
{12, 1920, 1080, 25}, /* p25 */
|
||||
{13, 1920, 1080, 50}, /* p50 */
|
||||
{14, 1920, 1080, 50}, /* i50 */
|
||||
{15, 1280, 720, 24}, /* p24 */
|
||||
{16, 1920, 1080, 24}, /* p24 */
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
struct resolution_bitmap resolutions_vesa[] = {
|
||||
{0, 800, 600, 30}, /* p30 */
|
||||
{1, 800, 600, 60}, /* p60 */
|
||||
{2, 1024, 768, 30}, /* p30 */
|
||||
{3, 1024, 768, 60}, /* p60 */
|
||||
{4, 1152, 854, 30}, /* p30 */
|
||||
{5, 1152, 854, 60}, /* p60 */
|
||||
{6, 1280, 768, 30}, /* p30 */
|
||||
{7, 1280, 768, 60}, /* p60 */
|
||||
{8, 1280, 800, 30}, /* p30 */
|
||||
{9, 1280, 800, 60}, /* p60 */
|
||||
{10, 1360, 768, 30}, /* p30 */
|
||||
{11, 1360, 768, 60}, /* p60 */
|
||||
{12, 1366, 768, 30}, /* p30 */
|
||||
{13, 1366, 768, 60}, /* p60 */
|
||||
{14, 1280, 1024, 30}, /* p30 */
|
||||
{15, 1280, 1024, 60}, /* p60 */
|
||||
{16, 1440, 1050, 30}, /* p30 */
|
||||
{17, 1440, 1050, 60}, /* p60 */
|
||||
{18, 1440, 900, 30}, /* p30 */
|
||||
{19, 1440, 900, 60}, /* p60 */
|
||||
{20, 1600, 900, 30}, /* p30 */
|
||||
{21, 1600, 900, 60}, /* p60 */
|
||||
{22, 1600, 1200, 30}, /* p30 */
|
||||
{23, 1600, 1200, 60}, /* p60 */
|
||||
{24, 1680, 1024, 30}, /* p30 */
|
||||
{25, 1680, 1024, 60}, /* p60 */
|
||||
{26, 1680, 1050, 30}, /* p30 */
|
||||
{27, 1680, 1050, 60}, /* p60 */
|
||||
{28, 1920, 1200, 30}, /* p30 */
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
struct resolution_bitmap resolutions_hh[] = {
|
||||
{0, 800, 480, 30}, /* p30 */
|
||||
{1, 800, 480, 60}, /* p60 */
|
||||
{2, 854, 480, 30}, /* p30 */
|
||||
{3, 854, 480, 60}, /* p60 */
|
||||
{4, 864, 480, 30}, /* p30 */
|
||||
{5, 864, 480, 60}, /* p60 */
|
||||
{6, 640, 360, 30}, /* p30 */
|
||||
{7, 640, 360, 60}, /* p60 */
|
||||
{8, 960, 540, 30}, /* p30 */
|
||||
{9, 960, 540, 60}, /* p60 */
|
||||
{10, 848, 480, 30}, /* p30 */
|
||||
{11, 848, 480, 60}, /* p60 */
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
void wfd_print_resolutions(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("CEA resolutions:\n");
|
||||
for (i = 0; resolutions_cea[i].hres != 0; i++) {
|
||||
printf("\t%2d %08x %4dx%4d@%d\n",
|
||||
resolutions_cea[i].index, 1 << resolutions_cea[i].index,
|
||||
resolutions_cea[i].hres, resolutions_cea[i].vres,
|
||||
resolutions_cea[i].fps);
|
||||
}
|
||||
printf("VESA resolutions:\n");
|
||||
for (i = 0; resolutions_vesa[i].hres != 0; i++) {
|
||||
printf("\t%2d %08x %4dx%4d@%d\n",
|
||||
resolutions_vesa[i].index, 1 << resolutions_vesa[i].index,
|
||||
resolutions_vesa[i].hres, resolutions_vesa[i].vres,
|
||||
resolutions_vesa[i].fps);
|
||||
}
|
||||
printf("HH resolutions:\n");
|
||||
for (i = 0; resolutions_hh[i].hres != 0; i++) {
|
||||
printf("\t%2d %08x %4dx%4d@%d\n",
|
||||
resolutions_hh[i].index, 1 << resolutions_hh[i].index,
|
||||
resolutions_hh[i].hres, resolutions_hh[i].vres,
|
||||
resolutions_hh[i].fps);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t vfd_generate_resolution_mask(unsigned int index)
|
||||
{
|
||||
return ((1 << (index + 1)) - 1);
|
||||
}
|
||||
|
||||
void vfd_dump_resolutions(uint32_t cea_mask, uint32_t vesa_mask, uint32_t hh_mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cea_mask) {
|
||||
cli_debug("CEA resolutions:");
|
||||
for (i = 0; resolutions_cea[i].hres != 0; i++)
|
||||
if ((1 << resolutions_cea[i].index) & cea_mask)
|
||||
cli_debug("\t%2d %08x %4dx%4d@%d\n",
|
||||
resolutions_cea[i].index, 1 << resolutions_cea[i].index,
|
||||
resolutions_cea[i].hres, resolutions_cea[i].vres,
|
||||
resolutions_cea[i].fps);
|
||||
}
|
||||
if (vesa_mask) {
|
||||
cli_debug("VESA resolutions:");
|
||||
for (i = 0; resolutions_vesa[i].hres != 0; i++)
|
||||
if ((1 << resolutions_vesa[i].index) & vesa_mask)
|
||||
cli_debug("\t%2d %08x %4dx%4d@%d\n",
|
||||
resolutions_vesa[i].index, 1 << resolutions_vesa[i].index,
|
||||
resolutions_vesa[i].hres, resolutions_vesa[i].vres,
|
||||
resolutions_vesa[i].fps);
|
||||
}
|
||||
if (hh_mask) {
|
||||
cli_debug("HH resolutions:");
|
||||
for (i = 0; resolutions_hh[i].hres != 0; i++)
|
||||
if ((1 << resolutions_hh[i].index) & hh_mask)
|
||||
cli_debug("\t%2d %08x %4dx%4d@%d\n",
|
||||
resolutions_hh[i].index, 1 << resolutions_hh[i].index,
|
||||
resolutions_hh[i].hres, resolutions_hh[i].vres,
|
||||
resolutions_hh[i].fps);
|
||||
}
|
||||
}
|
||||
|
||||
int vfd_get_cea_resolution(uint32_t mask, int *hres, int *vres)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mask)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; resolutions_cea[i].hres != 0; i++) {
|
||||
if ((1 << resolutions_cea[i].index) & mask) {
|
||||
*vres = resolutions_cea[i].vres;
|
||||
*hres = resolutions_cea[i].hres;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int vfd_get_vesa_resolution(uint32_t mask, int *hres, int *vres)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mask)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; resolutions_vesa[i].hres != 0; i++) {
|
||||
if ((1 << resolutions_vesa[i].index) & mask) {
|
||||
*vres = resolutions_vesa[i].vres;
|
||||
*hres = resolutions_vesa[i].hres;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int vfd_get_hh_resolution(uint32_t mask, int *hres, int *vres)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mask)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; resolutions_hh[i].hres != 0; i++) {
|
||||
if ((1 << resolutions_hh[i].index) & mask) {
|
||||
*vres = resolutions_hh[i].vres;
|
||||
*hres = resolutions_hh[i].hres;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
29
src/ctl/wfd.h
Normal file
29
src/ctl/wfd.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* MiracleCast - Wifi-Display/Miracast Implementation
|
||||
*
|
||||
* Copyright (c) 2014 Andrey Gusakov <andrey.gusakov@cogentembedded.com>
|
||||
* Copyright (c) 2013-2014 David Herrmann <dh.herrmann@gmail.com>
|
||||
*
|
||||
* MiracleCast is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MiracleCast is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with MiracleCast; If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WFD_H
|
||||
#define WFD_H
|
||||
|
||||
void wfd_print_resolutions(void);
|
||||
int vfd_get_cea_resolution(uint32_t mask, int *hres, int *vres);
|
||||
int vfd_get_vesa_resolution(uint32_t mask, int *hres, int *vres);
|
||||
int vfd_get_hh_resolution(uint32_t mask, int *hres, int *vres);
|
||||
|
||||
#endif /* WFD_H */
|
|
@ -363,7 +363,11 @@ void ctl_fn_peer_provision_discovery(struct ctl_peer *p,
|
|||
cli_printf("[" CLI_YELLOW "PROV" CLI_DEFAULT "] Peer: %s Type: %s PIN: %s\n",
|
||||
p->label, prov, pin);
|
||||
}
|
||||
|
||||
void ctl_fn_peer_go_neg_request(struct ctl_peer *p,
|
||||
const char *prov,
|
||||
const char *pin)
|
||||
{
|
||||
}
|
||||
void ctl_fn_peer_formation_failure(struct ctl_peer *p, const char *reason)
|
||||
{
|
||||
if (cli_running())
|
||||
|
|
|
@ -702,6 +702,12 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
|
|||
break;
|
||||
}
|
||||
|
||||
if (!lease) {
|
||||
/* check if requested address free */
|
||||
lease = add_lease(dhcp_server, OFFER_TIME,
|
||||
packet.chaddr, htonl(requested_nip));
|
||||
}
|
||||
|
||||
if (lease && requested_nip == lease->lease_nip) {
|
||||
debug(dhcp_server, "Sending ACK");
|
||||
send_ACK(dhcp_server, &packet,
|
||||
|
|
|
@ -1549,6 +1549,18 @@ int rtsp_message_readv_basic(struct rtsp_message *m,
|
|||
if (out_u32)
|
||||
*out_u32 = u32;
|
||||
|
||||
break;
|
||||
case RTSP_TYPE_HEX32:
|
||||
if (sscanf(entry, "%" SCNx32, &u32) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
out_u32 = va_arg(*args, uint32_t*);
|
||||
if (out_u32)
|
||||
*out_u32 = u32;
|
||||
|
||||
break;
|
||||
case RTSP_TYPE_SKIP:
|
||||
/* just increment token */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -1588,8 +1600,13 @@ int rtsp_message_readv(struct rtsp_message *m,
|
|||
|
||||
for ( ; *types; ++types) {
|
||||
r = rtsp_message_readv_basic(m, *types, args);
|
||||
if (r < 0)
|
||||
if (r < 0) {
|
||||
if (m->iter_body)
|
||||
rtsp_message_exit_body(m);
|
||||
if (m->iter_header)
|
||||
rtsp_message_exit_header(m);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -45,6 +45,8 @@ enum {
|
|||
#define RTSP_TYPE_STRING 's'
|
||||
#define RTSP_TYPE_INT32 'i'
|
||||
#define RTSP_TYPE_UINT32 'u'
|
||||
#define RTSP_TYPE_HEX32 'h'
|
||||
#define RTSP_TYPE_SKIP '*'
|
||||
#define RTSP_TYPE_RAW '&'
|
||||
#define RTSP_TYPE_HEADER_START '<'
|
||||
#define RTSP_TYPE_HEADER_END '>'
|
||||
|
|
|
@ -308,6 +308,7 @@ static const sd_bus_vtable peer_dbus_vtable[] = {
|
|||
0,
|
||||
SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_SIGNAL("ProvisionDiscovery", "ss", 0),
|
||||
SD_BUS_SIGNAL("GoNegRequest", "ss", 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
@ -408,6 +409,31 @@ void peer_dbus_provision_discovery(struct peer *p,
|
|||
log_vERR(r);
|
||||
}
|
||||
|
||||
void peer_dbus_go_neg_request(struct peer *p,
|
||||
const char *type,
|
||||
const char *pin)
|
||||
{
|
||||
_shl_free_ char *node = NULL;
|
||||
int r;
|
||||
|
||||
if (!type)
|
||||
return;
|
||||
if (!pin)
|
||||
pin = "";
|
||||
|
||||
node = peer_dbus_get_path(p);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
r = sd_bus_emit_signal(p->l->m->bus,
|
||||
node,
|
||||
"org.freedesktop.miracle.wifi.Peer",
|
||||
"GoNegRequest",
|
||||
"ss", type, pin);
|
||||
if (r < 0)
|
||||
log_vERR(r);
|
||||
}
|
||||
|
||||
void peer_dbus_formation_failure(struct peer *p, const char *reason)
|
||||
{
|
||||
_shl_free_ char *node = NULL;
|
||||
|
|
|
@ -200,6 +200,16 @@ void peer_supplicant_provision_discovery(struct peer *p,
|
|||
peer_dbus_provision_discovery(p, prov, pin);
|
||||
}
|
||||
|
||||
void peer_supplicant_go_neg_request(struct peer *p,
|
||||
const char *prov,
|
||||
const char *pin)
|
||||
{
|
||||
if (!p || !p->public)
|
||||
return;
|
||||
|
||||
peer_dbus_go_neg_request(p, prov, pin);
|
||||
}
|
||||
|
||||
void peer_supplicant_formation_failure(struct peer *p,
|
||||
const char *reason)
|
||||
{
|
||||
|
|
|
@ -94,6 +94,17 @@ struct supplicant {
|
|||
bool p2p_scanning : 1;
|
||||
};
|
||||
|
||||
/* Device Password ID */
|
||||
enum wps_dev_password_id {
|
||||
DEV_PW_DEFAULT = 0x0000,
|
||||
DEV_PW_USER_SPECIFIED = 0x0001,
|
||||
DEV_PW_MACHINE_SPECIFIED = 0x0002,
|
||||
DEV_PW_REKEY = 0x0003,
|
||||
DEV_PW_PUSHBUTTON = 0x0004,
|
||||
DEV_PW_REGISTRAR_SPECIFIED = 0x0005,
|
||||
DEV_PW_NFC_CONNECTION_HANDOVER = 0x0007
|
||||
};
|
||||
|
||||
static void supplicant_failed(struct supplicant *s);
|
||||
static void supplicant_peer_drop_group(struct supplicant_peer *sp);
|
||||
|
||||
|
@ -998,11 +1009,50 @@ static void supplicant_event_p2p_prov_disc_pbc_req(struct supplicant *s,
|
|||
free(sp->pin);
|
||||
sp->pin = NULL;
|
||||
|
||||
peer_supplicant_provision_discovery(sp->p, sp->prov, sp->pin);
|
||||
}
|
||||
|
||||
static void supplicant_event_p2p_go_neg_request(struct supplicant *s,
|
||||
struct wpas_message *ev)
|
||||
{
|
||||
struct supplicant_peer *sp;
|
||||
const char *mac;
|
||||
int r;
|
||||
|
||||
|
||||
r = wpas_message_read(ev, "s", &mac);
|
||||
if (r < 0) {
|
||||
log_debug("no p2p-mac in P2P-GO-NEG-REQUEST information: %s",
|
||||
wpas_message_get_raw(ev));
|
||||
return;
|
||||
}
|
||||
|
||||
sp = find_peer_by_p2p_mac(s, mac);
|
||||
if (!sp) {
|
||||
log_debug("stale P2P-GO-NEG-REQUEST: %s",
|
||||
wpas_message_get_raw(ev));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* prov should be set by previous
|
||||
* P2P-PROV-DISC-PBC-REQ
|
||||
* P2P-PROV-DISC-SHOW-PIN
|
||||
* or P2P-PROV-DISC-ENTER-PIN
|
||||
* if not set pbc mode
|
||||
*/
|
||||
|
||||
if (!sp->prov) {
|
||||
sp->prov = strdup("pbc");
|
||||
free(sp->pin);
|
||||
sp->pin = NULL;
|
||||
}
|
||||
|
||||
if (!sp->g) {
|
||||
log_debug("PBC provision discovery for %s", mac);
|
||||
peer_supplicant_provision_discovery(sp->p, sp->prov, sp->pin);
|
||||
log_debug("GO Negotiation Request from %s", mac);
|
||||
peer_supplicant_go_neg_request(sp->p, sp->prov, sp->pin);
|
||||
} else {
|
||||
log_debug("PBC provision discovery for already connected peer %s",
|
||||
log_debug("GO Negotiation Request from already connected peer %s",
|
||||
mac);
|
||||
}
|
||||
}
|
||||
|
@ -1051,13 +1101,7 @@ static void supplicant_event_p2p_prov_disc_show_pin(struct supplicant *s,
|
|||
free(sp->pin);
|
||||
sp->pin = u;
|
||||
|
||||
if (!sp->g) {
|
||||
log_debug("DISPLAY provision discovery for %s", mac);
|
||||
peer_supplicant_provision_discovery(sp->p, sp->prov, sp->pin);
|
||||
} else {
|
||||
log_debug("DISPLAY provision discovery for already connected peer %s",
|
||||
mac);
|
||||
}
|
||||
peer_supplicant_provision_discovery(sp->p, sp->prov, sp->pin);
|
||||
}
|
||||
|
||||
static void supplicant_event_p2p_prov_disc_enter_pin(struct supplicant *s,
|
||||
|
@ -1091,13 +1135,7 @@ static void supplicant_event_p2p_prov_disc_enter_pin(struct supplicant *s,
|
|||
free(sp->pin);
|
||||
sp->pin = NULL;
|
||||
|
||||
if (!sp->g) {
|
||||
log_debug("PIN provision discovery for %s", mac);
|
||||
peer_supplicant_provision_discovery(sp->p, sp->prov, sp->pin);
|
||||
} else {
|
||||
log_debug("PIN provision discovery for already connected peer %s",
|
||||
mac);
|
||||
}
|
||||
peer_supplicant_provision_discovery(sp->p, sp->prov, sp->pin);
|
||||
}
|
||||
|
||||
static void supplicant_event_p2p_go_neg_success(struct supplicant *s,
|
||||
|
@ -1340,6 +1378,14 @@ static void supplicant_event_ap_sta_disconnected(struct supplicant *s,
|
|||
return;
|
||||
}
|
||||
|
||||
if (sp->s->pending == sp) {
|
||||
sp->s->pending = NULL;
|
||||
if (sp->p->connected)
|
||||
peer_supplicant_connected_changed(sp->p, false);
|
||||
else
|
||||
peer_supplicant_formation_failure(sp->p, "disconnected");
|
||||
}
|
||||
|
||||
log_debug("unbind peer %s from its group", p2p_mac);
|
||||
supplicant_peer_drop_group(sp);
|
||||
}
|
||||
|
@ -1394,6 +1440,8 @@ static void supplicant_event(struct supplicant *s, struct wpas_message *m)
|
|||
supplicant_event_p2p_prov_disc_enter_pin(s, m);
|
||||
else if (!strcmp(name, "P2P-GO-NEG-SUCCESS"))
|
||||
supplicant_event_p2p_go_neg_success(s, m);
|
||||
else if (!strcmp(name, "P2P-GO-NEG-REQUEST"))
|
||||
supplicant_event_p2p_go_neg_request(s, m);
|
||||
else if (!strcmp(name, "P2P-GROUP-STARTED"))
|
||||
supplicant_event_p2p_group_started(s, m);
|
||||
else if (!strcmp(name, "P2P-GROUP-REMOVED"))
|
||||
|
@ -1621,7 +1669,7 @@ static int supplicant_status_fn(struct wpas *w,
|
|||
|
||||
r = wpas_message_append(m, "ss",
|
||||
"device_name",
|
||||
s->l->friendly_name ? : "unknown");
|
||||
s->l->friendly_name ? : "Miracle");
|
||||
if (r < 0) {
|
||||
log_vERR(r);
|
||||
goto error;
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#include "util.h"
|
||||
#include "wifid.h"
|
||||
|
||||
#define DO_NOT_RELY_UDEV 1
|
||||
|
||||
const char *arg_wpa_bindir = "/usr/bin";
|
||||
unsigned int arg_wpa_loglevel = LOG_NOTICE;
|
||||
|
||||
|
@ -97,9 +99,9 @@ static void manager_add_udev_link(struct manager *m,
|
|||
|
||||
link_set_friendly_name(l, m->friendly_name);
|
||||
|
||||
#if 0
|
||||
#if DO_NOT_RELY_UDEV
|
||||
if (udev_device_has_tag(d, "miracle"))
|
||||
#endif
|
||||
#endif
|
||||
link_set_managed(l, true);
|
||||
}
|
||||
|
||||
|
@ -135,10 +137,14 @@ static int manager_udev_fn(sd_event_source *source,
|
|||
link_renamed(l, ifname);
|
||||
}
|
||||
|
||||
#if DO_NOT_RELY_UDEV
|
||||
link_set_managed(l, true);
|
||||
#else
|
||||
if (udev_device_has_tag(d, "miracle"))
|
||||
link_set_managed(l, true);
|
||||
else
|
||||
link_set_managed(l, false);
|
||||
#endif
|
||||
} else {
|
||||
manager_add_udev_link(m, d);
|
||||
}
|
||||
|
@ -331,7 +337,7 @@ static void manager_read_name(struct manager *m)
|
|||
|
||||
r = sd_bus_message_read(rep, "s", &name);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
name = "undefined";
|
||||
|
||||
if (shl_isempty(name)) {
|
||||
log_warning("no hostname set on systemd.hostname1, using: %s",
|
||||
|
|
|
@ -101,6 +101,9 @@ void peer_supplicant_wfd_subelements_changed(struct peer *p);
|
|||
void peer_supplicant_provision_discovery(struct peer *p,
|
||||
const char *prov,
|
||||
const char *pin);
|
||||
void peer_supplicant_go_neg_request(struct peer *p,
|
||||
const char *prov,
|
||||
const char *pin);
|
||||
void peer_supplicant_formation_failure(struct peer *p, const char *reason);
|
||||
void peer_supplicant_connected_changed(struct peer *p, bool connected);
|
||||
|
||||
|
@ -109,6 +112,9 @@ void peer_dbus_properties_changed(struct peer *p, const char *prop, ...);
|
|||
void peer_dbus_provision_discovery(struct peer *p,
|
||||
const char *prov,
|
||||
const char *pin);
|
||||
void peer_dbus_go_neg_request(struct peer *p,
|
||||
const char *type,
|
||||
const char *pin);
|
||||
void peer_dbus_formation_failure(struct peer *p, const char *reason);
|
||||
void peer_dbus_added(struct peer *p);
|
||||
void peer_dbus_removed(struct peer *p);
|
||||
|
|
Loading…
Reference in a new issue