Commit a0c000ec authored by Sylvain Berfini's avatar Sylvain Berfini 🎩

Wrapped CallStats + incall stats display

parent 69f028c1
......@@ -74,7 +74,7 @@
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</CompileAsWinRT>
<CompileAsWinRT Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</CompileAsWinRT>
<GenerateXMLDocumentationFiles Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</GenerateXMLDocumentationFiles>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir)../submodules\oRTP\include;$(ProjectDir)../submodules/mediastreamer2/include;$(ProjectDir)../submodules/linphone;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">$(ProjectDir)../submodules\oRTP\include;$(ProjectDir)../submodules/mediastreamer2/include;$(ProjectDir)../submodules/linphone;$(ProjectDir)../submodules/linphone/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ExceptionHandling Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">SyncCThrow</ExceptionHandling>
</ClCompile>
<Link>
......
......@@ -34,9 +34,7 @@ Linphone::Core::LinphoneCallLog^ Linphone::Core::LinphoneCall::GetCallLog()
Linphone::Core::LinphoneCallStats^ Linphone::Core::LinphoneCall::GetAudioStats()
{
std::lock_guard<std::recursive_mutex> lock(g_apiLock);
//TODO
return nullptr;
return (Linphone::Core::LinphoneCallStats^) Linphone::Core::Utils::CreateLinphoneCallStats((void*) linphone_call_get_audio_stats(this->call), this->call);
}
Linphone::Core::LinphoneCallParams^ Linphone::Core::LinphoneCall::GetRemoteParams()
......
......@@ -125,6 +125,7 @@ namespace Linphone
private:
friend class Linphone::Core::Utils;
friend ref class Linphone::Core::LinphoneCore;
friend ref class Linphone::Core::LinphoneCallStats;
LinphoneCall(::LinphoneCall *call);
~LinphoneCall();
......
#include "LinphoneCallStats.h"
#include "LinphoneCall.h"
#include "Server.h"
#include "coreapi\private.h"
Linphone::Core::MediaType Linphone::Core::LinphoneCallStats::GetMediaType()
{
//TODO
return Linphone::Core::MediaType::Audio;
return (Linphone::Core::MediaType) this->stats->type;
}
Linphone::Core::IceState Linphone::Core::LinphoneCallStats::GetIceState()
{
//TODO
return Linphone::Core::IceState::Failed;
return (Linphone::Core::IceState) this->stats->ice_state;
}
float Linphone::Core::LinphoneCallStats::GetDownloadBandwidth()
{
//TODO
return -1;
return this->stats->download_bandwidth;
}
float Linphone::Core::LinphoneCallStats::GetUploadBandwidth()
{
//TODO
return -1;
return this->stats->upload_bandwidth;
}
float Linphone::Core::LinphoneCallStats::GetSenderLossRate()
{
//TODO
return -1;
const report_block_t *srb = NULL;
if (!stats || !stats->sent_rtcp)
return 0.0;
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
if (stats->sent_rtcp->b_cont != NULL)
msgpullup(stats->sent_rtcp, -1);
if (rtcp_is_SR(stats->sent_rtcp))
srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
else if (rtcp_is_RR(stats->sent_rtcp))
srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
if (!srb)
return 0.0;
return (100.0 * report_block_get_fraction_lost(srb) / 256.0);
}
float Linphone::Core::LinphoneCallStats::GetReceiverLossRate()
{
//TODO
return -1;
const report_block_t* rrb = NULL;
if (!stats || !stats->received_rtcp)
return 0.0;
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
if (stats->received_rtcp->b_cont != NULL)
msgpullup(stats->received_rtcp, -1);
if (rtcp_is_RR(stats->received_rtcp))
rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
else if (rtcp_is_SR(stats->received_rtcp))
rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
if (!rrb)
return 0.0;
return (100.0 * report_block_get_fraction_lost(rrb) / 256.0);
}
float Linphone::Core::LinphoneCallStats::GetSenderInterarrivalJitter()
{
//TODO
return -1;
const ::LinphoneCallParams* params;
const ::PayloadType* pt;
const report_block_t* srb = NULL;
if (!stats || !this->call || !stats->sent_rtcp)
return 0.0;
params = linphone_call_get_current_params(this->call);
if (!params)
return 0.0;
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
if (stats->sent_rtcp->b_cont != NULL)
msgpullup(stats->sent_rtcp, -1);
if (rtcp_is_SR(stats->sent_rtcp))
srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
else if (rtcp_is_RR(stats->sent_rtcp))
srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
if (!srb)
return 0.0;
if (stats->type == LINPHONE_CALL_STATS_AUDIO)
pt = linphone_call_params_get_used_audio_codec(params);
else
pt = linphone_call_params_get_used_video_codec(params);
if (!pt || (pt->clock_rate == 0))
return 0.0;
return ((float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate);
}
float Linphone::Core::LinphoneCallStats::GetReceiverInterarrivalJitter()
{
//TODO
return -1;
const ::LinphoneCallParams* params;
const ::PayloadType* pt;
const report_block_t* rrb = NULL;
if (!stats || !this->call || !stats->received_rtcp)
return 0.0;
params = linphone_call_get_current_params(this->call);
if (!params)
return 0.0;
/* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
if (stats->received_rtcp->b_cont != NULL)
msgpullup(stats->received_rtcp, -1);
if (rtcp_is_SR(stats->received_rtcp))
rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
else if (rtcp_is_RR(stats->received_rtcp))
rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
if (!rrb)
return 0.0;
if (stats->type == LINPHONE_CALL_STATS_AUDIO)
pt = linphone_call_params_get_used_audio_codec(params);
else
pt = linphone_call_params_get_used_video_codec(params);
if (!pt || (pt->clock_rate == 0))
return 0.0;
return ((float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate);
}
float Linphone::Core::LinphoneCallStats::GetRoundTripDelay()
{
//TODO
return -1;
return this->stats->round_trip_delay;
}
int64 Linphone::Core::LinphoneCallStats::GetLatePacketsCumulativeNumber()
{
//TODO
return -1;
rtp_stats_t rtp_stats;
if (!stats || !this->call)
return 0;
memset(&rtp_stats, 0, sizeof(rtp_stats));
if (stats->type == LINPHONE_CALL_STATS_AUDIO)
audio_stream_get_local_rtp_stats(this->call->audiostream, &rtp_stats);
#ifdef VIDEO_ENABLED
else
video_stream_get_local_rtp_stats(this->call->videostream, &rtp_stats);
#endif
return rtp_stats.outoftime;
}
float Linphone::Core::LinphoneCallStats::GetJitterBufferSize()
{
//TODO
return -1;
return this->stats->jitter_stats.jitter_buffer_size_ms;
}
float Linphone::Core::LinphoneCallStats::GetLocalLossRate()
{
return this->stats->local_loss_rate;
}
float Linphone::Core::LinphoneCallStats::GetLocalLateRate()
{
return this->stats->local_late_rate;
}
Linphone::Core::LinphoneCallStats::LinphoneCallStats(::LinphoneCallStats *call_stats, ::LinphoneCall *call) :
stats(call_stats),
call(call)
{
}
Linphone::Core::LinphoneCallStats::~LinphoneCallStats()
{
}
#pragma once
#include "LinphoneCore.h"
namespace Linphone
{
namespace Core
......@@ -53,6 +55,19 @@ namespace Linphone
/// Gets the jitter buffer size in milliseconds.
/// </summary>
float GetJitterBufferSize();
float GetLocalLossRate();
float GetLocalLateRate();
private:
friend class Linphone::Core::Utils;
friend ref class Linphone::Core::LinphoneCore;
LinphoneCallStats(::LinphoneCallStats* stats, ::LinphoneCall *call);
~LinphoneCallStats();
::LinphoneCallStats *stats;
::LinphoneCall *call;
};
}
}
\ No newline at end of file
......@@ -858,6 +858,7 @@ void Linphone::Core::LinphoneCore::TunnelAddServerAndMirror(Platform::String^ ho
return;
const char* h = Linphone::Core::Utils::pstoccs(host);
//TODO
//LinphoneTunnelConfig* config = linphone_tunnel_config_new();
//linphone_tunnel_config_set_host(config, h);
//linphone_tunnel_config_set_port(config, port);
......
......@@ -5,6 +5,7 @@
#include "LinphoneProxyConfig.h"
#include "LinphoneCallLog.h"
#include "LinphoneCallParams.h"
#include "LinphoneCallStats.h"
#include "LpConfig.h"
#include "PayloadType.h"
......@@ -43,7 +44,7 @@ Platform::String^ Linphone::Core::Utils::cctops(const char* cc)
return ref new Platform::String(w_char);
}
void Linphone::Core::Utils::LinphoneCoreSetLogHandler(void *logfunc)
void Linphone::Core::Utils::LinphoneCoreSetLogHandler(void* logfunc)
{
std::lock_guard<std::recursive_mutex> lock(g_apiLock);
linphone_core_set_log_handler(static_cast<OrtpLogFunc>(logfunc));
......@@ -55,7 +56,7 @@ void Linphone::Core::Utils::LinphoneCoreSetLogLevel(int loglevel)
linphone_core_set_log_level(static_cast<OrtpLogLevel>(loglevel));
}
Platform::Object^ Linphone::Core::Utils::CreateLpConfig(void *config)
Platform::Object^ Linphone::Core::Utils::CreateLpConfig(void* config)
{
return ref new Linphone::Core::LpConfig((::LpConfig *)config);
}
......@@ -65,7 +66,7 @@ Platform::Object^ Linphone::Core::Utils::CreateLpConfig(Platform::String^ config
return ref new Linphone::Core::LpConfig(configPath, factoryConfigPath);
}
Platform::Object^ Linphone::Core::Utils::CreatePayloadType(void *pt)
Platform::Object^ Linphone::Core::Utils::CreatePayloadType(void* pt)
{
return ref new Linphone::Core::PayloadType((::PayloadType *)pt);
}
......@@ -80,17 +81,17 @@ Platform::Object^ Linphone::Core::Utils::CreateLinphoneAddress(void* address)
return ref new Linphone::Core::LinphoneAddress((::LinphoneAddress *)address);
}
Platform::Object^ Linphone::Core::Utils::CreateLinphoneAddressFromUri(const char *uri)
Platform::Object^ Linphone::Core::Utils::CreateLinphoneAddressFromUri(const char* uri)
{
return ref new Linphone::Core::LinphoneAddress(uri);
}
Platform::Object^ Linphone::Core::Utils::CreateLinphoneAuthInfo(void *auth_info)
Platform::Object^ Linphone::Core::Utils::CreateLinphoneAuthInfo(void* auth_info)
{
return ref new Linphone::Core::LinphoneAuthInfo((::LinphoneAuthInfo *)auth_info);
}
Platform::Object^ Linphone::Core::Utils::CreateLinphoneProxyConfig(void *proxy_config)
Platform::Object^ Linphone::Core::Utils::CreateLinphoneProxyConfig(void* proxy_config)
{
return ref new Linphone::Core::LinphoneProxyConfig((::LinphoneProxyConfig *)proxy_config);
}
......@@ -104,3 +105,8 @@ Platform::Object^ Linphone::Core::Utils::CreateLinphoneCallParams(void* callPara
{
return ref new Linphone::Core::LinphoneCallParams((::LinphoneCallParams *)callParams);
}
Platform::Object^ Linphone::Core::Utils::CreateLinphoneCallStats(void* callStats, void* call)
{
return ref new Linphone::Core::LinphoneCallStats((::LinphoneCallStats *)callStats, (::LinphoneCall *)call);
}
\ No newline at end of file
......@@ -26,7 +26,7 @@ namespace Linphone
/// Define a log handler.
/// <param name="logfunc">The function pointer of the log handler.</param>
/// </summary>
static void LinphoneCoreSetLogHandler(void *logfunc);
static void LinphoneCoreSetLogHandler(void* logfunc);
/// <summary>
/// Define the log level.
......@@ -39,7 +39,7 @@ namespace Linphone
/// <summary>
/// Creates a C++/CX LpConfig object using pointer to C structure.
/// </summary>
static Platform::Object^ CreateLpConfig(void *config);
static Platform::Object^ CreateLpConfig(void* config);
/// <summary>
/// Creates a C++/CX LpConfig object using the path to linphonerc files.
......@@ -49,7 +49,7 @@ namespace Linphone
/// <summary>
/// Creates a C++/CX PayloadType object using pointer to C structure.
/// </summary>
static Platform::Object^ CreatePayloadType(void *pt);
static Platform::Object^ CreatePayloadType(void* pt);
/// <summary>
/// Creates a C++/CX LinphoneCall object using pointer to C structure.
......@@ -64,17 +64,17 @@ namespace Linphone
/// <summary>
/// Creates a C++/CX LinphoneAddress object using an URI.
/// </summary>
static Platform::Object^ CreateLinphoneAddressFromUri(const char *uri);
static Platform::Object^ CreateLinphoneAddressFromUri(const char* uri);
/// <summary>
/// Creates a C++/CX LinphoneAuthInfo object using pointer to C structure.
/// </summary>
static Platform::Object^ CreateLinphoneAuthInfo(void *auth_info);
static Platform::Object^ CreateLinphoneAuthInfo(void* auth_info);
/// <summary>
/// Creates a C++/CX LinphoneProxyConfig object using pointer to C structure.
/// </summary>
static Platform::Object^ CreateLinphoneProxyConfig(void *proxy_config);
static Platform::Object^ CreateLinphoneProxyConfig(void* proxy_config);
/// <summary>
/// Creates a C++/CX LinphoneCallLog object using pointer to C structure.
......@@ -86,6 +86,11 @@ namespace Linphone
/// </summary>
static Platform::Object^ CreateLinphoneCallParams(void* callParams);
/// <summary>
/// Creates a C++/CX LinphoneCallStats object using pointer to C structure.
/// </summary>
static Platform::Object^ CreateLinphoneCallStats(void* callStats, void* call);
private:
static std::string wstos(std::wstring ws);
......
......@@ -164,6 +164,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="Assets\AppBar\clear.png" />
<Content Include="Assets\AppBar\stats.png" />
<Content Include="Assets\linphonerc" />
<Content Include="Assets\linphonerc-factory" />
<Content Include="Assets\rootca.pem" />
......
......@@ -570,6 +570,51 @@ namespace Linphone.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Audio codec.
/// </summary>
public static string StatAudioPayload {
get {
return ResourceManager.GetString("StatAudioPayload", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Download.
/// </summary>
public static string StatDownloadBW {
get {
return ResourceManager.GetString("StatDownloadBW", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to stats.
/// </summary>
public static string Stats {
get {
return ResourceManager.GetString("Stats", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Stats.
/// </summary>
public static string StatsMenu {
get {
return ResourceManager.GetString("StatsMenu", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Upload.
/// </summary>
public static string StatUploadBW {
get {
return ResourceManager.GetString("StatUploadBW", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Transport.
/// </summary>
......
......@@ -329,4 +329,19 @@ http://www.linphone.org/m/help
<data name="HistoryAll" xml:space="preserve">
<value>All</value>
</data>
<data name="Stats" xml:space="preserve">
<value>stats</value>
</data>
<data name="StatAudioPayload" xml:space="preserve">
<value>Audio codec</value>
</data>
<data name="StatDownloadBW" xml:space="preserve">
<value>Download</value>
</data>
<data name="StatsMenu" xml:space="preserve">
<value>Stats</value>
</data>
<data name="StatUploadBW" xml:space="preserve">
<value>Upload</value>
</data>
</root>
\ No newline at end of file
......@@ -23,18 +23,28 @@
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<StackPanel x:Name="emptyPanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
<TextBlock Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<StackPanel x:Name="statsPanel" Grid.Row="1" Margin="12,17,0,28" Visibility="Collapsed">
<TextBlock Text="{Binding Path=LocalizedResources.StatsMenu, Source={StaticResource LocalizedStrings}}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="DownBw" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="UpBw" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PType" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1">
<Grid x:Name="ContentPanel" Grid.Row="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
......@@ -64,6 +74,7 @@
<Grid Grid.Row="3" Margin="0,25,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
......@@ -148,9 +159,24 @@
</StackPanel>
</ToggleButton>
<ToggleButton
x:Name="stats"
Grid.Row="2"
Grid.Column="0"
BorderThickness="0"
Margin="-10"
Click="stats_Click_1"
Visibility="Visible"
Background="{StaticResource PhoneChromeBrush}">
<StackPanel Orientation="Vertical">
<Image x:Name="statsImg" Source="/Assets/AppBar/stats.png" Stretch="None"/>
<TextBlock HorizontalAlignment="Center" FontSize="20" Text="{Binding Path=LocalizedResources.Stats, Source={StaticResource LocalizedStrings}}" TextWrapping="Wrap" Margin="5,0,5,10"/>
</StackPanel>
</ToggleButton>
<Grid
x:Name="numpad"
Grid.Row="2"
Grid.Row="3"
Grid.ColumnSpan="3"
Visibility="Collapsed">
<Grid.RowDefinitions>
......
using Linphone.Core;
using Linphone.Model;
using Linphone.Resources;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
......@@ -129,6 +131,13 @@ namespace Linphone.Views
LinphoneManager.Instance.CallController.NotifyUnmuted();
}
private void stats_Click_1(object sender, RoutedEventArgs e)
{
bool areStatsVisible = (bool)stats.IsChecked;
emptyPanel.Visibility = areStatsVisible ? Visibility.Collapsed : Visibility.Visible;
statsPanel.Visibility = areStatsVisible ? Visibility.Visible : Visibility.Collapsed;
}
/// <summary>
/// Called when the mute status of the microphone changes.
/// </summary>
......@@ -183,6 +192,20 @@ namespace Linphone.Views
Status.Dispatcher.BeginInvoke(delegate()
{
Status.Text = mm.ToString("00") + ":" + ss.ToString("00");
LinphoneCallStats stats = call.GetAudioStats();
if (stats != null)
{
DownBw.Text = String.Format(AppResources.StatDownloadBW + ": {0} kbit/s", stats.GetDownloadBandwidth());
UpBw.Text = String.Format(AppResources.StatUploadBW + ": {0} kbit/s", stats.GetUploadBandwidth());
}
LinphoneCallParams param = call.GetCurrentParamsCopy();
PayloadType pt = param.GetUsedAudioCodec();
if (pt != null)
{
PType.Text = AppResources.StatAudioPayload + ": " + pt.GetMimeType() + "/" + pt.GetClockRate();
}
});
} catch {
timer.Dispose();
......@@ -196,6 +219,7 @@ namespace Linphone.Views
speaker.Visibility = isDialpadVisible ? Visibility.Collapsed : Visibility.Visible;
microphone.Visibility = isDialpadVisible ? Visibility.Collapsed : Visibility.Visible;
numpad.Visibility = isDialpadVisible ? Visibility.Visible : Visibility.Collapsed;
stats.Visibility = isDialpadVisible ? Visibility.Collapsed : Visibility.Visible;
}
private void Numpad_Click_1(object sender, RoutedEventArgs e)
......
linphone @ 8b571c2e
Subproject commit da89be1d127cc89640830795ba71f7f841b9ecf6
Subproject commit 8b571c2edfb8e05f9e822c7c0516f000efd27fd8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment