Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (14)
......@@ -138,6 +138,10 @@ typedef struct
bool b_spatial_audio_supported;
enum au_dev au_dev;
/* For debug purpose, to print when specific latency changed */
vlc_tick_t output_latency_ticks;
vlc_tick_t io_buffer_duration_ticks;
/* sw gain */
float soft_gain;
bool soft_mute;
......@@ -154,6 +158,39 @@ enum port_type
PORT_TYPE_HEADPHONES
};
static vlc_tick_t
GetLatency(audio_output_t *p_aout)
{
aout_sys_t *p_sys = p_aout->sys;
Float64 unit_s;
vlc_tick_t latency_us = 0, us;
bool changed = false;
us = vlc_tick_from_sec([p_sys->avInstance outputLatency]);
if (us != p_sys->output_latency_ticks)
{
msg_Dbg(p_aout, "Current device has a new outputLatency of %" PRId64 "us", us);
p_sys->output_latency_ticks = us;
changed = true;
}
latency_us += us;
us = vlc_tick_from_sec([p_sys->avInstance IOBufferDuration]);
if (us != p_sys->io_buffer_duration_ticks)
{
msg_Dbg(p_aout, "Current device has a new IOBufferDuration of %" PRId64 "us", us);
p_sys->io_buffer_duration_ticks = us;
changed = true;
}
latency_us += us;
if (changed)
msg_Dbg(p_aout, "Current device has a new total latency of %" PRId64 "us",
latency_us);
return latency_us;
}
#pragma mark -
#pragma mark AVAudioSession route and output handling
......@@ -181,12 +218,7 @@ enum port_type
|| routeChangeReason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable)
aout_RestartRequest(p_aout, AOUT_RESTART_OUTPUT);
else
{
const vlc_tick_t latency_us =
vlc_tick_from_sec([p_sys->avInstance outputLatency]);
ca_SetDeviceLatency(p_aout, latency_us);
msg_Dbg(p_aout, "Current device has a new latency of %lld us", latency_us);
}
ca_ResetDeviceLatency(p_aout);
}
- (void)handleInterruption:(NSNotification *)notification
......@@ -520,6 +552,8 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
aout_FormatPrint(p_aout, "VLC is looking for:", fmt);
p_sys->au_unit = NULL;
p_sys->output_latency_ticks = 0;
p_sys->io_buffer_duration_ticks = 0;
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:p_sys->aoutWrapper
......@@ -580,11 +614,7 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
if (err != noErr)
ca_LogWarn("failed to set IO mode");
const vlc_tick_t latency_us =
vlc_tick_from_sec([p_sys->avInstance outputLatency]);
msg_Dbg(p_aout, "Current device has a latency of %lld us", latency_us);
ret = au_Initialize(p_aout, p_sys->au_unit, fmt, NULL, latency_us, NULL);
ret = au_Initialize(p_aout, p_sys->au_unit, fmt, NULL, 0, GetLatency, NULL);
if (ret != VLC_SUCCESS)
goto error;
......
......@@ -1036,7 +1036,8 @@ WarnConfiguration(audio_output_t *p_aout)
* StartAnalog: open and setup a HAL AudioUnit to do PCM audio output
*/
static int
StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt,
vlc_tick_t latency_us)
{
aout_sys_t *p_sys = p_aout->sys;
OSStatus err = noErr;
......@@ -1090,8 +1091,8 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
/* Do the last VLC aout setups */
bool warn_configuration;
int ret = au_Initialize(p_aout, p_sys->au_unit, fmt, layout, 0,
&warn_configuration);
int ret = au_Initialize(p_aout, p_sys->au_unit, fmt, layout, latency_us,
NULL, &warn_configuration);
if (ret != VLC_SUCCESS)
goto error;
......@@ -1364,7 +1365,7 @@ StartSPDIF(audio_output_t * p_aout, audio_sample_format_t *fmt)
return VLC_EGENERIC;
}
ret = ca_Initialize(p_aout, fmt, 0);
ret = ca_Initialize(p_aout, fmt, 0, NULL);
if (ret != VLC_SUCCESS)
{
AudioDeviceDestroyIOProcID(p_sys->i_selected_dev, p_sys->i_procID);
......@@ -1475,6 +1476,58 @@ Stop(audio_output_t *p_aout)
kAudioObjectPropertyScopeGlobal);
}
static vlc_tick_t
GetLatency(audio_output_t *p_aout, const audio_sample_format_t *fmt)
{
aout_sys_t *p_sys = p_aout->sys;
UInt32 i_latency_samples;
vlc_tick_t i_latency_us, i_device_latency_us = 0, i_device_offset_us = 0,
i_stream_latency_us = 0;
/* Get device latency */
int ret = AO_GET1PROP(p_sys->i_selected_dev, UInt32, &i_latency_samples,
kAudioDevicePropertyLatency,
kAudioObjectPropertyScopeOutput);
if (ret == VLC_SUCCESS)
i_device_latency_us = vlc_tick_from_samples(i_latency_samples, fmt->i_rate);
else
msg_Warn(p_aout, "failed to get kAudioDevicePropertyLatency");
/* Get device safety offset */
ret = AO_GET1PROP(p_sys->i_selected_dev, UInt32, &i_latency_samples,
kAudioDevicePropertySafetyOffset,
kAudioObjectPropertyScopeOutput);
if (ret == VLC_SUCCESS)
i_device_offset_us = vlc_tick_from_samples(i_latency_samples, fmt->i_rate);
else
msg_Warn(p_aout, "failed to get kAudioDevicePropertySafetyOffset");
AudioStreamID sid;
/* Get stream latency */
ret = AO_GET1PROP(p_sys->i_selected_dev, AudioStreamID, &sid,
kAudioDevicePropertyStreams, kAudioObjectPropertyScopeOutput);
if (ret == VLC_SUCCESS)
{
ret = AO_GET1PROP(sid, UInt32, &i_latency_samples,
kAudioStreamPropertyLatency,
kAudioObjectPropertyScopeOutput);
if (ret == VLC_SUCCESS)
i_stream_latency_us = vlc_tick_from_samples(i_latency_samples, fmt->i_rate);
else
msg_Warn(p_aout, "failed to get kAudioStreamPropertyLatency");
}
else
msg_Warn(p_aout, "failed to get kAudioDevicePropertyStreams");
i_latency_us = i_device_latency_us + i_device_offset_us + i_stream_latency_us;
msg_Dbg(p_aout, "Current device has a latency of %" PRId64 " us "
"(device: %" PRId64 " us, offset: %" PRId64 " us, stream: %" PRId64 " us)", i_latency_us,
i_device_latency_us, i_device_offset_us, i_stream_latency_us);
return i_latency_us;
}
static int
Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
{
......@@ -1573,16 +1626,7 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal);
/* get device latency */
UInt32 i_latency_samples;
vlc_tick_t i_latency_us = 0;
int ret = AO_GET1PROP(p_sys->i_selected_dev, UInt32, &i_latency_samples,
kAudioDevicePropertyLatency,
kAudioObjectPropertyScopeOutput);
if (ret == VLC_SUCCESS)
i_latency_us += vlc_tick_from_samples(i_latency_samples, fmt->i_rate);
msg_Dbg(p_aout, "Current device has a latency of %lld us", i_latency_us);
vlc_tick_t i_latency_us = GetLatency(p_aout, fmt);
/* Check for Digital mode or Analog output mode */
if (do_spdif)
......@@ -1595,7 +1639,7 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
}
else
{
if (StartAnalog(p_aout, fmt) == VLC_SUCCESS)
if (StartAnalog(p_aout, fmt, i_latency_us) == VLC_SUCCESS)
{
msg_Dbg(p_aout, "analog output successfully opened");
fmt->channel_type = AUDIO_CHANNEL_TYPE_BITMAP;
......
......@@ -25,6 +25,8 @@
#include "coreaudio_common.h"
#include <CoreAudio/CoreAudioTypes.h>
#define TIMING_REPORT_DELAY_TICKS VLC_TICK_FROM_MS(1000)
static inline uint64_t
BytesToFrames(struct aout_sys_common *p_sys, size_t i_bytes)
{
......@@ -37,6 +39,12 @@ FramesToTicks(struct aout_sys_common *p_sys, int64_t i_nb_frames)
return vlc_tick_from_samples(i_nb_frames, p_sys->i_rate);
}
static inline vlc_tick_t
BytesToTicks(struct aout_sys_common *p_sys, size_t i_bytes)
{
return FramesToTicks(p_sys, BytesToFrames(p_sys, i_bytes));
}
static inline size_t
FramesToBytes(struct aout_sys_common *p_sys, uint64_t i_frames)
{
......@@ -49,6 +57,12 @@ TicksToFrames(struct aout_sys_common *p_sys, vlc_tick_t i_ticks)
return samples_from_vlc_tick(i_ticks, p_sys->i_rate);
}
static inline size_t
TicksToBytes(struct aout_sys_common *p_sys, vlc_tick_t i_ticks)
{
return FramesToBytes(p_sys, TicksToFrames(p_sys, i_ticks));
}
/**
* Convert a relative audio host time to vlc_ticks
*
......@@ -62,19 +76,6 @@ HostTimeToTick(struct aout_sys_common *p_sys, int64_t i_host_time)
return VLC_TICK_FROM_NS(i_host_time * p_sys->tinfo.numer / p_sys->tinfo.denom);
}
/**
* Convert relative vlc_ticks to an audio host time
*
* \warning This function may only be used to convert relative
* vlc_ticks, as vlc_ticks do not have the same origin
* as the audio host clock!
*/
static inline int64_t
TickToHostTime(struct aout_sys_common *p_sys, vlc_tick_t i_ticks)
{
return NS_FROM_VLC_TICK(i_ticks * p_sys->tinfo.denom / p_sys->tinfo.numer);
}
static void
ca_ClearOutBuffers(audio_output_t *p_aout)
{
......@@ -83,8 +84,6 @@ ca_ClearOutBuffers(audio_output_t *p_aout)
block_ChainRelease(p_sys->p_out_chain);
p_sys->p_out_chain = NULL;
p_sys->pp_out_last = &p_sys->p_out_chain;
p_sys->i_out_size = 0;
}
static inline void
......@@ -124,9 +123,9 @@ ca_Open(audio_output_t *p_aout)
assert(p_sys->tinfo.denom != 0 && p_sys->tinfo.numer != 0);
vlc_sem_init(&p_sys->flush_sem, 0);
lock_init(p_sys);
p_sys->p_out_chain = NULL;
p_sys->pp_out_last = &p_sys->p_out_chain;
p_sys->chans_to_reorder = 0;
p_aout->play = ca_Play;
......@@ -137,126 +136,128 @@ ca_Open(audio_output_t *p_aout)
return VLC_SUCCESS;
}
static vlc_tick_t
GetLatency(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
vlc_tick_t dev_latency_ticks =
p_sys->get_latency != NULL ? p_sys->get_latency(p_aout)
: p_sys->i_dev_latency_ticks;
/* Add the AudioUnit latency to the auhal/audiounit_ios latency */
if (p_sys->au != NULL)
{
Float64 unit_s;
if (AudioUnitGetProperty(p_sys->au, kAudioUnitProperty_Latency,
kAudioUnitScope_Global, 0, &unit_s,
&(UInt32) { sizeof(unit_s) }) != noErr)
unit_s = 0;
vlc_tick_t us = vlc_tick_from_sec(unit_s);
if (us != p_sys->au_latency_ticks)
{
msg_Dbg(p_aout, "Adding AudioUnit latency: %" PRId64 "us", us);
p_sys->au_latency_ticks = us;
}
dev_latency_ticks += us;
}
return dev_latency_ticks;
}
/* Called from render callbacks. No lock, wait, and IO here */
void
ca_Render(audio_output_t *p_aout, uint64_t i_host_time,
uint8_t *p_output, size_t i_requested, bool *is_silence)
ca_Render(audio_output_t *p_aout, uint64_t host_time,
uint8_t *data, size_t bytes, bool *is_silence)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
vlc_tick_t i_now_ticks = vlc_tick_now();
const vlc_tick_t host_delay_ticks = host_time == 0 ? 0
: HostTimeToTick(p_sys, host_time - mach_absolute_time());
const vlc_tick_t bytes_ticks = BytesToTicks(p_sys, bytes);
lock_lock(p_sys);
const vlc_tick_t now_ticks = vlc_tick_now();
const vlc_tick_t end_ticks = now_ticks + bytes_ticks + host_delay_ticks;
if (p_sys->b_do_flush)
{
ca_ClearOutBuffers(p_aout);
/* Signal that the renderer is flushed */
p_sys->b_do_flush = false;
vlc_sem_post(&p_sys->flush_sem);
}
lock_lock(p_sys);
if (unlikely(p_sys->i_first_render_host_time == 0))
goto drop;
if (p_sys->b_paused)
{
p_sys->i_render_host_time = i_host_time;
goto drop;
}
/* Start deferred: write silence (zeros) until we reach the first render
* host time. */
if (unlikely(p_sys->i_first_render_host_time > i_host_time ))
if (!p_sys->started)
{
/* Convert the requested bytes into host time and check that it does
* not overlap between the first_render host time and the current one.
* */
const vlc_tick_t i_requested_ticks =
FramesToTicks(p_sys, BytesToFrames(p_sys, i_requested));
const int64_t i_requested_host_time =
TickToHostTime(p_sys, i_requested_ticks);
if (p_sys->i_first_render_host_time >= i_host_time + i_requested_host_time)
size_t tocopy;
if (p_sys->first_play_date == VLC_TICK_INVALID)
tocopy = bytes;
else
{
/* Fill the buffer with silence */
goto drop;
/* Write silence to reach the first play date */
vlc_tick_t silence_ticks = p_sys->first_play_date - end_ticks
- GetLatency(p_aout) + bytes_ticks;
if (silence_ticks > 0)
{
tocopy = TicksToBytes(p_sys, silence_ticks);
if (tocopy > bytes)
tocopy = bytes;
}
else
tocopy = 0;
}
/* Write silence to reach the first_render host time */
const vlc_tick_t i_silence_ticks =
HostTimeToTick(p_sys, p_sys->i_first_render_host_time - i_host_time);
const size_t i_silence_bytes =
FramesToBytes(p_sys, TicksToFrames(p_sys, i_silence_ticks));
assert(i_silence_bytes <= i_requested);
memset(p_output, 0, i_silence_bytes);
if (tocopy > 0)
{
memset(data, 0, tocopy);
i_requested -= i_silence_bytes;
p_output += i_silence_bytes;
data += tocopy;
bytes -= tocopy;
/* Start the first rendering */
if (bytes == 0 && is_silence != NULL)
*is_silence = true;
}
}
p_sys->i_render_host_time = i_host_time;
size_t i_copied = 0;
block_t *p_block = p_sys->p_out_chain;
while (p_block != NULL && i_requested != 0)
while (bytes > 0)
{
size_t i_tocopy = __MIN(i_requested, p_block->i_buffer);
if (unlikely(p_sys->b_muted))
memset(p_output, 0, i_tocopy);
else
memcpy(p_output, p_block->p_buffer, i_tocopy);
i_requested -= i_tocopy;
i_copied += i_tocopy;
p_output += i_tocopy;
vlc_frame_t *f = p_sys->p_out_chain;
if (f == NULL)
goto drop;
size_t tocopy = f->i_buffer > bytes ? bytes : f->i_buffer;
p_sys->i_out_size -= tocopy;
p_sys->i_total_bytes += tocopy;
if (i_tocopy == p_block->i_buffer)
if (!p_sys->started
|| (p_sys->timing_report_last_written_bytes >=
p_sys->timing_report_delay_bytes))
{
block_t *p_release = p_block;
p_block = p_block->p_next;
block_Release(p_release);
p_sys->timing_report_last_written_bytes = 0;
vlc_tick_t pos_ticks = BytesToTicks(p_sys, p_sys->i_total_bytes);
aout_TimingReport(p_aout, end_ticks + GetLatency(p_aout), pos_ticks);
}
else
{
assert(i_requested == 0);
p_block->p_buffer += i_tocopy;
p_block->i_buffer -= i_tocopy;
}
}
p_sys->p_out_chain = p_block;
if (!p_sys->p_out_chain)
p_sys->pp_out_last = &p_sys->p_out_chain;
p_sys->i_out_size -= i_copied;
p_sys->i_total_bytes += i_copied;
p_sys->timing_report_last_written_bytes += tocopy;
/* Pad with 0 */
if (i_requested > 0)
{
assert(p_sys->i_out_size == 0);
p_sys->i_underrun_size += i_requested;
memset(p_output, 0, i_requested);
}
p_sys->started = true;
if (is_silence != NULL)
*is_silence = p_sys->b_muted;
memcpy(data, f->p_buffer, tocopy);
/* Convert host time to ticks */
vlc_tick_t i_host_ticks = HostTimeToTick(p_sys, i_host_time - mach_absolute_time())
+ i_now_ticks;
data += tocopy;
bytes -= tocopy;
f->i_buffer -= tocopy;
f->p_buffer += tocopy;
/* Report a timing every seconds */
if (p_sys->i_last_latency_ticks == VLC_TICK_INVALID
|| i_host_ticks - p_sys->i_last_latency_ticks >= VLC_TICK_FROM_SEC(1))
{
vlc_tick_t frames_tick = FramesToTicks(p_sys,
BytesToFrames(p_sys, p_sys->i_total_bytes))
+ p_sys->i_dev_latency_ticks;
if (f->i_buffer == 0)
{
p_sys->p_out_chain = f->p_next;
if (p_sys->p_out_chain == NULL)
p_sys->pp_out_last = &p_sys->p_out_chain;
aout_TimingReport(p_aout, i_host_ticks, frames_tick);
p_sys->i_last_latency_ticks = i_host_ticks;
block_Release(f);
}
}
lock_unlock(p_sys);
......@@ -264,43 +265,27 @@ ca_Render(audio_output_t *p_aout, uint64_t i_host_time,
return;
drop:
memset(p_output, 0, i_requested);
memset(data, 0, bytes);
if (is_silence != NULL)
*is_silence = true;
lock_unlock(p_sys);
}
static vlc_tick_t
ca_GetLatencyLocked(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
const int64_t i_out_frames = BytesToFrames(p_sys, p_sys->i_out_size);
return FramesToTicks(p_sys, i_out_frames)
+ p_sys->i_dev_latency_ticks;
}
void
ca_Flush(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
lock_lock(p_sys);
assert(!p_sys->b_do_flush);
if (p_sys->b_paused)
ca_ClearOutBuffers(p_aout);
else
{
p_sys->b_do_flush = true;
lock_unlock(p_sys);
vlc_sem_wait(&p_sys->flush_sem);
lock_lock(p_sys);
}
lock_lock(p_sys);
p_sys->i_render_host_time = p_sys->i_first_render_host_time = 0;
p_sys->i_last_latency_ticks = VLC_TICK_INVALID;
p_sys->started = false;
p_sys->i_out_size = 0;
p_sys->i_total_bytes = 0;
p_sys->first_play_date = VLC_TICK_INVALID;
p_sys->timing_report_last_written_bytes = 0;
ca_ClearOutBuffers(p_aout);
lock_unlock(p_sys);
p_sys->b_played = false;
......@@ -314,6 +299,7 @@ ca_Pause(audio_output_t * p_aout, bool pause, vlc_tick_t date)
lock_lock(p_sys);
p_sys->b_paused = pause;
p_sys->started = false;
lock_unlock(p_sys);
}
......@@ -340,20 +326,17 @@ ca_Play(audio_output_t * p_aout, block_t * p_block, vlc_tick_t date)
lock_lock(p_sys);
if (p_sys->i_render_host_time == 0)
if (!p_sys->started)
{
/* Setup the first render time, this date must be updated until the
* first (non-silence/zero) frame is rendered by the render callback.
* Once the rendering is truly started, the date can be ignored. */
/* We can't convert date to host time directly since the clock source
* may be different (MONOTONIC vs continue during sleep). The solution
* is to convert it to a relative time and then add it to
* mach_absolute_time() */
const vlc_tick_t first_render_delay = date - vlc_tick_now()
- ca_GetLatencyLocked(p_aout);
p_sys->i_first_render_host_time
= mach_absolute_time() + TickToHostTime(p_sys, first_render_delay);
vlc_tick_t now = vlc_tick_now();
p_sys->first_play_date = date - BytesToTicks(p_sys, p_sys->i_out_size);
if (p_sys->first_play_date > now)
msg_Dbg(p_aout, "deferring start (%"PRId64" us)",
p_sys->first_play_date - now);
else
msg_Dbg(p_aout, "starting late (%"PRId64" us)",
p_sys->first_play_date - now);
}
p_sys->i_out_size += p_block->i_buffer;
......@@ -374,22 +357,30 @@ ca_Play(audio_output_t * p_aout, block_t * p_block, vlc_tick_t date)
int
ca_Initialize(audio_output_t *p_aout, const audio_sample_format_t *fmt,
vlc_tick_t i_dev_latency_ticks)
vlc_tick_t i_dev_latency_ticks, get_latency_cb get_latency)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
p_sys->au = NULL;
p_sys->au_latency_ticks = 0;
p_sys->i_underrun_size = 0;
p_sys->b_paused = false;
p_sys->started = false;
p_sys->b_muted = false;
p_sys->i_render_host_time = p_sys->i_first_render_host_time = 0;
p_sys->i_last_latency_ticks = VLC_TICK_INVALID;
p_sys->i_out_size = 0;
p_sys->i_total_bytes = 0;
p_sys->first_play_date = VLC_TICK_INVALID;
p_sys->timing_report_last_written_bytes = 0;
p_sys->i_rate = fmt->i_rate;
p_sys->i_bytes_per_frame = fmt->i_bytes_per_frame;
p_sys->i_frame_length = fmt->i_frame_length;
p_sys->i_dev_latency_ticks = i_dev_latency_ticks;
if (get_latency != NULL)
p_sys->get_latency = get_latency;
else
p_sys->i_dev_latency_ticks = i_dev_latency_ticks;
p_sys->timing_report_delay_bytes = TicksToBytes(p_sys, TIMING_REPORT_DELAY_TICKS);
ca_ClearOutBuffers(p_aout);
p_sys->b_played = false;
......@@ -411,29 +402,17 @@ ca_SetAliveState(audio_output_t *p_aout, bool alive)
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
lock_lock(p_sys);
bool b_sem_post = false;
p_sys->b_paused = !alive;
if (!alive && p_sys->b_do_flush)
{
ca_ClearOutBuffers(p_aout);
p_sys->b_played = false;
p_sys->b_do_flush = false;
b_sem_post = true;
}
lock_unlock(p_sys);
if (b_sem_post)
vlc_sem_post(&p_sys->flush_sem);
}
void ca_SetDeviceLatency(audio_output_t *p_aout, vlc_tick_t i_dev_latency_ticks)
void ca_ResetDeviceLatency(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
lock_lock(p_sys);
p_sys->i_dev_latency_ticks = i_dev_latency_ticks;
/* Trigger aout_TimingReport() to be called from the next render callback */
p_sys->timing_report_last_written_bytes = p_sys->timing_report_delay_bytes;
lock_unlock(p_sys);
}
......@@ -480,13 +459,18 @@ RenderCallback(void *p_data, AudioUnitRenderActionFlags *ioActionFlags,
VLC_UNUSED(ioActionFlags);
VLC_UNUSED(inTimeStamp);
VLC_UNUSED(inBusNumber);
audio_output_t * p_aout = p_data;
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
assert(inNumberFrames == BytesToFrames(p_sys, ioData->mBuffers[0].mDataByteSize));
VLC_UNUSED(inNumberFrames);
uint64_t i_host_time = (inTimeStamp->mFlags & kAudioTimeStampHostTimeValid)
? inTimeStamp->mHostTime : 0;
bool is_silence;
ca_Render(p_data, i_host_time, ioData->mBuffers[0].mData,
ca_Render(p_aout, i_host_time, ioData->mBuffers[0].mData,
ioData->mBuffers[0].mDataByteSize, &is_silence);
if (is_silence)
*ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence;
......@@ -718,9 +702,6 @@ static int
MapInputLayout(audio_output_t *p_aout, const audio_sample_format_t *fmt,
AudioChannelLayout **inlayoutp, size_t *inlayout_size)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
uint32_t chans_out[AOUT_CHAN_MAX] = { 0, };
unsigned channels = aout_FormatNbChannels(fmt);
size_t size;
......@@ -763,8 +744,9 @@ MapInputLayout(audio_output_t *p_aout, const audio_sample_format_t *fmt,
int
au_Initialize(audio_output_t *p_aout, AudioUnit au, audio_sample_format_t *fmt,
const AudioChannelLayout *outlayout, vlc_tick_t i_dev_latency_ticks,
bool *warn_configuration)
get_latency_cb get_latency, bool *warn_configuration)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
int ret;
AudioChannelLayout *inlayout_buf = NULL;
const AudioChannelLayout *inlayout = NULL;
......@@ -886,12 +868,13 @@ au_Initialize(audio_output_t *p_aout, AudioUnit au, audio_sample_format_t *fmt,
return VLC_EGENERIC;
}
ret = ca_Initialize(p_aout, fmt, i_dev_latency_ticks);
ret = ca_Initialize(p_aout, fmt, i_dev_latency_ticks, get_latency);
if (ret != VLC_SUCCESS)
{
AudioUnitUninitialize(au);
return VLC_EGENERIC;
}
p_sys->au = au;
return VLC_SUCCESS;
}
......
......@@ -45,27 +45,36 @@
#define ca_LogErr(fmt) msg_Err(p_aout, fmt ", OSStatus: %d", (int) err)
#define ca_LogWarn(fmt) msg_Warn(p_aout, fmt ", OSStatus: %d", (int) err)
typedef vlc_tick_t (*get_latency_cb)(audio_output_t *);
struct aout_sys_common
{
/* The following is owned by common.c (initialized from ca_Open) */
AudioUnit au; /* Can be NULL (pass-through) */
mach_timebase_info_data_t tinfo;
size_t i_underrun_size;
bool started;
bool b_paused;
bool b_muted;
bool b_do_flush;
size_t i_out_size;
bool b_played;
block_t *p_out_chain;
block_t **pp_out_last;
uint64_t i_render_host_time;
uint64_t i_first_render_host_time;
vlc_tick_t i_last_latency_ticks;
/* Size of the frame FIFO */
size_t i_out_size;
/* Size written via the render callback */
uint64_t i_total_bytes;
vlc_sem_t flush_sem;
/* Date when the data callback should start to process audio */
vlc_tick_t first_play_date;
/* Bytes written since the last timing report */
size_t timing_report_last_written_bytes;
/* Number of bytes to write before sending a timing report */
size_t timing_report_delay_bytes;
/* Last AudioUnit Latency, for debug/log purpose */
vlc_tick_t au_latency_ticks;
union lock
{
......@@ -83,6 +92,7 @@ struct aout_sys_common
uint8_t chan_table[AOUT_CHAN_MAX];
/* ca_TimeGet extra latency, in vlc ticks */
vlc_tick_t i_dev_latency_ticks;
get_latency_cb get_latency;
};
int ca_Open(audio_output_t *p_aout);
......@@ -101,20 +111,20 @@ void ca_MuteSet(audio_output_t * p_aout, bool mute);
void ca_Play(audio_output_t * p_aout, block_t * p_block, vlc_tick_t date);
int ca_Initialize(audio_output_t *p_aout, const audio_sample_format_t *fmt,
vlc_tick_t i_dev_latency_ticks);
vlc_tick_t i_dev_latency_ticks, get_latency_cb get_latency);
void ca_Uninitialize(audio_output_t *p_aout);
void ca_SetAliveState(audio_output_t *p_aout, bool alive);
void ca_SetDeviceLatency(audio_output_t *p_aout, vlc_tick_t i_dev_latency_ticks);
void ca_ResetDeviceLatency(audio_output_t *p_aout);
AudioUnit au_NewOutputInstance(audio_output_t *p_aout, OSType comp_sub_type);
int au_Initialize(audio_output_t *p_aout, AudioUnit au,
audio_sample_format_t *fmt,
const AudioChannelLayout *outlayout, vlc_tick_t i_dev_latency_ticks,
bool *warn_configuration);
get_latency_cb get_latency, bool *warn_configuration);
void au_Uninitialize(audio_output_t *p_aout, AudioUnit au);
......