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 (13)
......@@ -76,7 +76,7 @@ static char default_device_b[1] = "";
typedef struct
{
aout_stream_t *stream; /**< Underlying audio output stream */
struct aout_stream_owner *stream; /**< Underlying audio output stream */
audio_output_t *aout;
IMMDeviceEnumerator *it; /**< Device enumerator, NULL when exiting */
IMMDevice *dev; /**< Selected output device, NULL if none */
......@@ -94,9 +94,9 @@ typedef struct
signed char requested_mute; /**< Requested mute, negative if none */
wchar_t *acquired_device; /**< Acquired device identifier, NULL if none */
bool request_device_restart;
CRITICAL_SECTION lock;
CONDITION_VARIABLE work;
CONDITION_VARIABLE ready;
HANDLE work_event;
vlc_mutex_t lock;
vlc_cond_t ready;
vlc_thread_t thread; /**< Thread for audio session control */
} aout_sys_t;
......@@ -129,7 +129,9 @@ static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
HRESULT hr;
EnterMTA();
hr = aout_stream_TimeGet(sys->stream, delay);
vlc_mutex_lock(&sys->lock);
hr = aout_stream_owner_TimeGet(sys->stream, delay);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return SUCCEEDED(hr) ? 0 : -1;
......@@ -138,13 +140,11 @@ static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
static void Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
{
aout_sys_t *sys = aout->sys;
HRESULT hr;
EnterMTA();
hr = aout_stream_Play(sys->stream, block, date);
LeaveMTA();
vlc_FromHR(aout, hr);
vlc_mutex_lock(&sys->lock);
aout_stream_owner_AppendBlock(sys->stream, block, date);
vlc_mutex_unlock(&sys->lock);
SetEvent(sys->work_event);
}
static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
......@@ -153,7 +153,9 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
HRESULT hr;
EnterMTA();
hr = aout_stream_Pause(sys->stream, paused);
vlc_mutex_lock(&sys->lock);
hr = aout_stream_owner_Pause(sys->stream, paused);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
vlc_FromHR(aout, hr);
......@@ -166,7 +168,9 @@ static void Flush(audio_output_t *aout)
HRESULT hr;
EnterMTA();
hr = aout_stream_Flush(sys->stream);
vlc_mutex_lock(&sys->lock);
hr = aout_stream_owner_Flush(sys->stream);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
vlc_FromHR(aout, hr);
......@@ -194,11 +198,11 @@ static int VolumeSet(audio_output_t *aout, float vol)
{
aout_sys_t *sys = aout->sys;
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
int ret = VolumeSetLocked(aout, vol);
aout_GainRequest(aout, sys->gain);
WakeConditionVariable(&sys->work);
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
SetEvent(sys->work_event);
return ret;
}
......@@ -206,10 +210,10 @@ static int MuteSet(audio_output_t *aout, bool mute)
{
aout_sys_t *sys = aout->sys;
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
sys->requested_mute = mute;
WakeConditionVariable(&sys->work);
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
SetEvent(sys->work_event);
return 0;
}
......@@ -280,9 +284,7 @@ vlc_AudioSessionEvents_OnSimpleVolumeChanged(IAudioSessionEvents *this,
msg_Dbg(aout, "simple volume changed: %f, muting %sabled", vol,
mute ? "en" : "dis");
EnterCriticalSection(&sys->lock);
WakeConditionVariable(&sys->work); /* implicit state: vol & mute */
LeaveCriticalSection(&sys->lock);
SetEvent(sys->work_event); /* implicit state: vol & mute */
(void) ctx;
return S_OK;
}
......@@ -582,14 +584,14 @@ vlc_MMNotificationClient_OnDefaultDeviceChange(IMMNotificationClient *this,
if (role != eConsole)
return S_OK;
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
if (sys->acquired_device == NULL || sys->acquired_device == default_device)
{
msg_Dbg(aout, "default device changed: %ls", wid);
sys->request_device_restart = true;
aout_RestartRequest(aout, AOUT_RESTART_OUTPUT);
}
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
return S_OK;
}
......@@ -736,9 +738,9 @@ static int DeviceRequestLocked(audio_output_t *aout)
sys->request_device_restart = false;
WakeConditionVariable(&sys->work);
SetEvent(sys->work_event);
while (sys->requested_device != NULL)
SleepConditionVariableCS(&sys->ready, &sys->lock, INFINITE);
vlc_cond_wait(&sys->ready, &sys->lock);
if (sys->stream != NULL && sys->dev != NULL)
/* Request restart of stream with the new device */
......@@ -775,12 +777,101 @@ static int DeviceRestartLocked(audio_output_t *aout)
static int DeviceSelect(audio_output_t *aout, const char *id)
{
aout_sys_t *sys = aout->sys;
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
int ret = DeviceSelectLocked(aout, id);
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
return ret;
}
/**
* Main loop
*
* Adjust volume as long as device is unchanged
* */
static void MMSessionMainloop(audio_output_t *aout, ISimpleAudioVolume *volume)
{
aout_sys_t *sys = aout->sys;
HRESULT hr;
bool report_volume = true;
bool report_mute = true;
while (sys->requested_device == NULL)
{
if (volume != NULL)
{
if (sys->requested_volume >= 0.f)
{
hr = ISimpleAudioVolume_SetMasterVolume(volume, sys->requested_volume, NULL);
if (FAILED(hr))
msg_Err(aout, "cannot set master volume (error 0x%lX)",
hr);
report_volume = true;
sys->requested_volume = -1.f;
}
if (report_volume)
{
float level;
hr = ISimpleAudioVolume_GetMasterVolume(volume, &level);
if (SUCCEEDED(hr))
aout_VolumeReport(aout, cbrtf(level * sys->gain));
else
msg_Err(aout, "cannot get master volume (error 0x%lX)", hr);
report_volume = false;
}
if (sys->requested_mute >= 0)
{
BOOL mute = sys->requested_mute ? TRUE : FALSE;
hr = ISimpleAudioVolume_SetMute(volume, mute, NULL);
if (FAILED(hr))
msg_Err(aout, "cannot set mute (error 0x%lX)", hr);
report_mute = true;
sys->requested_mute = -1;
}
if (report_mute)
{
BOOL mute;
hr = ISimpleAudioVolume_GetMute(volume, &mute);
if (SUCCEEDED(hr))
aout_MuteReport(aout, mute != FALSE);
else
msg_Err(aout, "cannot get mute (error 0x%lX)", hr);
report_mute = false;
}
}
DWORD ev_count = 1;
HANDLE events[2] = {
sys->work_event,
NULL
};
/* Don't listen to the stream event if the block fifo is empty */
if (sys->stream != NULL && sys->stream->chain != NULL)
events[ev_count++] = sys->stream->buffer_ready_event;
vlc_mutex_unlock(&sys->lock);
WaitForMultipleObjects(ev_count, events, FALSE, INFINITE);
vlc_mutex_lock(&sys->lock);
if (sys->stream != NULL)
{
hr = aout_stream_owner_PlayAll(sys->stream);
/* Don't call vlc_FromHR here since this function waits for the
* current thread */
if (unlikely(hr == AUDCLNT_E_DEVICE_INVALIDATED ||
hr == AUDCLNT_E_RESOURCES_INVALIDATED))
{
sys->requested_device = default_device;
/* The restart of the stream will be requested asynchronously */
}
}
}
}
/*** Initialization / deinitialization **/
/** MMDevice audio output thread.
* This thread takes cares of the audio session control. Inconveniently enough,
......@@ -839,7 +930,7 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
}
sys->requested_device = NULL;
WakeConditionVariable(&sys->ready);
vlc_cond_signal(&sys->ready);
if (SUCCEEDED(hr))
{ /* Report actual device */
......@@ -961,52 +1052,9 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
else
msg_Err(aout, "cannot activate endpoint volume (error 0x%lX)", hr);
/* Main loop (adjust volume as long as device is unchanged) */
while (sys->requested_device == NULL)
{
if (volume != NULL)
{
float level;
level = sys->requested_volume;
if (level >= 0.f)
{
hr = ISimpleAudioVolume_SetMasterVolume(volume, level, NULL);
if (FAILED(hr))
msg_Err(aout, "cannot set master volume (error 0x%lX)",
hr);
}
sys->requested_volume = -1.f;
hr = ISimpleAudioVolume_GetMasterVolume(volume, &level);
if (SUCCEEDED(hr))
aout_VolumeReport(aout, cbrtf(level * sys->gain));
else
msg_Err(aout, "cannot get master volume (error 0x%lX)", hr);
BOOL mute;
hr = ISimpleAudioVolume_GetMute(volume, &mute);
if (FAILED(hr))
msg_Err(aout, "cannot get mute (error 0x%lX)", hr);
if (sys->requested_mute >= 0)
{
mute = sys->requested_mute ? TRUE : FALSE;
hr = ISimpleAudioVolume_SetMute(volume, mute, NULL);
if (FAILED(hr))
msg_Err(aout, "cannot set mute (error 0x%lX)", hr);
}
sys->requested_mute = -1;
MMSessionMainloop(aout, volume);
if (SUCCEEDED(hr))
aout_MuteReport(aout, mute != FALSE);
}
SleepConditionVariableCS(&sys->work, &sys->lock, INFINITE);
}
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
if (endpoint != NULL)
IAudioEndpointVolume_Release(endpoint);
......@@ -1036,7 +1084,7 @@ static HRESULT MMSession(audio_output_t *aout, IMMDeviceEnumerator *it)
IAudioSessionManager_Release(manager);
}
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
IMMDevice_Release(sys->dev);
sys->dev = NULL;
return S_OK;
......@@ -1064,14 +1112,18 @@ static void *MMThread(void *data)
if (FAILED(hr))
msg_Warn(aout, "cannot enumerate audio endpoints (error 0x%lX)", hr);
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
do
if (sys->requested_device == NULL || FAILED(MMSession(aout, it)))
SleepConditionVariableCS(&sys->work, &sys->lock, INFINITE);
{
vlc_mutex_unlock(&sys->lock);
WaitForSingleObject(sys->work_event, INFINITE);
vlc_mutex_lock(&sys->lock);
}
while (sys->it != NULL);
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(it,
&sys->device_events);
......@@ -1127,23 +1179,23 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
}
aout_stream_t *s = vlc_object_create(aout, sizeof (*s));
if (unlikely(s == NULL))
struct aout_stream_owner *owner =
aout_stream_owner_New(aout, sizeof (*owner), ActivateDevice);
if (unlikely(owner == NULL))
return -1;
s->owner.activate = ActivateDevice;
aout_stream_t *s = &owner->s;
EnterMTA();
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
if ((sys->request_device_restart && DeviceRestartLocked(aout) != 0)
|| sys->dev == NULL)
{
/* Error if the device restart failed or if a request previously
* failed. */
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
vlc_object_delete(s);
aout_stream_owner_Delete(owner);
return -1;
}
......@@ -1153,7 +1205,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
{
char *modlist = var_InheritString(aout, "mmdevice-backend");
HRESULT hr;
s->owner.device = sys->dev;
owner->device = sys->dev;
module = vlc_module_load(s, "aout stream", modlist,
false, aout_stream_Start, s, fmt, &hr);
......@@ -1208,17 +1260,20 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
}
}
LeaveCriticalSection(&sys->lock);
LeaveMTA();
if (module == NULL)
{
vlc_object_delete(s);
aout_stream_owner_Delete(owner);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return -1;
}
assert (sys->stream == NULL);
sys->stream = s;
sys->stream = owner;
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
aout_GainRequest(aout, sys->gain);
return 0;
}
......@@ -1230,10 +1285,10 @@ static void Stop(audio_output_t *aout)
assert(sys->stream != NULL);
EnterMTA();
aout_stream_Stop(sys->stream);
aout_stream_owner_Stop(sys->stream);
LeaveMTA();
vlc_object_delete(sys->stream);
aout_stream_owner_Delete(sys->stream);
sys->stream = NULL;
}
......@@ -1265,9 +1320,12 @@ static int Open(vlc_object_t *obj)
if (!var_CreateGetBool(aout, "volume-save"))
VolumeSetLocked(aout, var_InheritFloat(aout, "mmdevice-volume"));
InitializeCriticalSection(&sys->lock);
InitializeConditionVariable(&sys->work);
InitializeConditionVariable(&sys->ready);
vlc_mutex_init(&sys->lock);
vlc_cond_init(&sys->ready);
sys->work_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (unlikely(sys->work_event == NULL))
goto error;
aout_HotplugReport(aout, default_device_b, _("Default"));
......@@ -1308,10 +1366,10 @@ static int Open(vlc_object_t *obj)
goto error;
}
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
while (sys->requested_device != NULL)
SleepConditionVariableCS(&sys->ready, &sys->lock, INFINITE);
LeaveCriticalSection(&sys->lock);
vlc_cond_wait(&sys->ready, &sys->lock);
vlc_mutex_unlock(&sys->lock);
LeaveMTA(); /* Leave MTA after thread has entered MTA */
aout->start = Start;
......@@ -1327,7 +1385,8 @@ static int Open(vlc_object_t *obj)
return VLC_SUCCESS;
error:
DeleteCriticalSection(&sys->lock);
if (sys->work_event != NULL)
CloseHandle(sys->work_event);
free(sys);
return VLC_EGENERIC;
}
......@@ -1337,14 +1396,15 @@ static void Close(vlc_object_t *obj)
audio_output_t *aout = (audio_output_t *)obj;
aout_sys_t *sys = aout->sys;
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
sys->requested_device = default_device; /* break out of MMSession() loop */
sys->it = NULL; /* break out of MMThread() loop */
WakeConditionVariable(&sys->work);
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
SetEvent(sys->work_event);
vlc_join(sys->thread, NULL);
DeleteCriticalSection(&sys->lock);
CloseHandle(sys->work_event);
free(sys);
}
......
......@@ -41,14 +41,29 @@ struct aout_stream
HRESULT (*play)(aout_stream_t *, block_t *, vlc_tick_t);
HRESULT (*pause)(aout_stream_t *, bool);
HRESULT (*flush)(aout_stream_t *);
};
struct
{
void *device;
HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **);
} owner;
struct aout_stream_owner
{
aout_stream_t s;
void *device;
HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **);
HANDLE buffer_ready_event;
block_t *chain;
block_t **last;
};
/*
* "aout output" helpers
*/
static inline
struct aout_stream_owner *aout_stream_owner(aout_stream_t *s)
{
return container_of(s, struct aout_stream_owner, s);
}
/**
* Creates an audio output stream on a given Windows multimedia device.
* \param s audio output stream object to be initialized
......@@ -61,36 +76,140 @@ typedef HRESULT (*aout_stream_start_t)(aout_stream_t *s,
/**
* Destroys an audio output stream.
*/
static inline void aout_stream_Stop(aout_stream_t *s)
static inline
void aout_stream_owner_Stop(struct aout_stream_owner *owner)
{
owner->s.stop(&owner->s);
}
static inline
HRESULT aout_stream_owner_TimeGet(struct aout_stream_owner *owner,
vlc_tick_t *delay)
{
(s->stop)(s);
HRESULT hr = owner->s.time_get(&owner->s, delay);
if (SUCCEEDED(hr))
{
/* Add the block chain delay */
vlc_tick_t length;
block_ChainProperties(owner->chain, NULL, NULL, &length);
*delay += length;
}
return hr;
}
static inline HRESULT aout_stream_TimeGet(aout_stream_t *s, vlc_tick_t *delay)
static inline
HRESULT aout_stream_owner_Play(struct aout_stream_owner *owner,
block_t *block, vlc_tick_t date)
{
return (s->time_get)(s, delay);
return owner->s.play(&owner->s, block, date);
}
static inline HRESULT aout_stream_Play(aout_stream_t *s, block_t *block,
vlc_tick_t date)
static inline
HRESULT aout_stream_owner_Pause(struct aout_stream_owner *owner, bool paused)
{
return (s->play)(s, block, date);
return owner->s.pause(&owner->s, paused);
}
static inline HRESULT aout_stream_Pause(aout_stream_t *s, bool paused)
static inline
HRESULT aout_stream_owner_Flush(struct aout_stream_owner *owner)
{
return (s->pause)(s, paused);
block_ChainRelease(owner->chain);
owner->chain = NULL;
owner->last = &owner->chain;
return owner->s.flush(&owner->s);
}
static inline HRESULT aout_stream_Flush(aout_stream_t *s)
static inline
void aout_stream_owner_AppendBlock(struct aout_stream_owner *owner,
block_t *block, vlc_tick_t date)
{
return (s->flush)(s);
block->i_dts = date;
block_ChainLastAppend(&owner->last, block);
}
static inline
HRESULT aout_stream_owner_PlayAll(struct aout_stream_owner *owner)
{
HRESULT hr;
block_t *block = owner->chain, *next;
while (block != NULL)
{
next = block->p_next;
vlc_tick_t date = block->i_dts;
block->i_dts = VLC_TICK_INVALID;
hr = aout_stream_owner_Play(owner, block, date);
if (hr == S_FALSE)
return hr;
else
{
block = owner->chain = next;
if (FAILED(hr))
{
if (block == NULL)
owner->last = &owner->chain;
return hr;
}
}
}
owner->last = &owner->chain;
return S_OK;
}
static inline
void *aout_stream_owner_New(audio_output_t *aout, size_t size,
HRESULT (*activate)(void *device, REFIID, PROPVARIANT *, void **))
{
assert(size >= sizeof(struct aout_stream_owner));
void *obj = vlc_object_create(aout, size);
if (unlikely(obj == NULL))
return NULL;
struct aout_stream_owner *owner = obj;
owner->chain = NULL;
owner->last = &owner->chain;
owner->activate = activate;
owner->buffer_ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (unlikely(owner->buffer_ready_event == NULL))
{
vlc_object_delete(&owner->s);
return NULL;
}
return obj;
}
static inline
void aout_stream_owner_Delete(struct aout_stream_owner *owner)
{
CloseHandle(owner->buffer_ready_event);
vlc_object_delete(&owner->s);
}
/*
* "aout stream" helpers
*/
static inline
HRESULT aout_stream_Activate(aout_stream_t *s, REFIID iid,
PROPVARIANT *actparms, void **pv)
{
return s->owner.activate(s->owner.device, iid, actparms, pv);
struct aout_stream_owner *owner = aout_stream_owner(s);
return owner->activate(owner->device, iid, actparms, pv);
}
static inline
HANDLE aout_stream_GetBufferReadyEvent(aout_stream_t *s)
{
struct aout_stream_owner *owner = aout_stream_owner(s);
return owner->buffer_ready_event;
}
#endif
......@@ -313,8 +313,10 @@ static HRESULT Play(aout_stream_t *s, block_t *block, vlc_tick_t date)
if (block->i_nb_samples == 0)
break; /* done */
/* Out of buffer space, sleep */
vlc_tick_sleep(sys->frames * VLC_TICK_FROM_MS(500) / sys->rate);
block->i_length -= vlc_tick_from_samples(frames, sys->rate);
/* Out of buffer space, keep the block and notify the owner */
IAudioRenderClient_Release(render);
return S_FALSE;
}
IAudioRenderClient_Release(render);
out:
......@@ -902,8 +904,9 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict pfmt,
if (sys->s24s32)
msg_Dbg(s, "audio device configured as s24");
hr = IAudioClient_Initialize(sys->client, shared_mode, 0, buffer_duration,
0, pwf, sid);
hr = IAudioClient_Initialize(sys->client, shared_mode,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
buffer_duration, 0, pwf, sid);
CoTaskMemFree(pwf_closest);
if (FAILED(hr))
{
......@@ -911,6 +914,14 @@ static HRESULT Start(aout_stream_t *s, audio_sample_format_t *restrict pfmt,
goto error;
}
hr = IAudioClient_SetEventHandle(sys->client,
aout_stream_GetBufferReadyEvent(s));
if (FAILED(hr))
{
msg_Err(s, "cannot set audio client EventHandle (error 0x%lX)", hr);
goto error;
}
hr = IAudioClient_GetBufferSize(sys->client, &sys->frames);
if (FAILED(hr))
{
......
......@@ -55,7 +55,7 @@ static void LeaveMTA(void)
typedef struct
{
aout_stream_t *stream; /**< Underlying audio output stream */
struct aout_stream_owner *stream; /**< Underlying audio output stream */
module_t *module;
IAudioClient *client;
wchar_t* acquired_device;
......@@ -68,9 +68,12 @@ typedef struct
IActivateAudioInterfaceCompletionHandler client_locator;
vlc_sem_t async_completed;
LONG refs;
CRITICAL_SECTION lock;
} aout_sys_t;
vlc_mutex_t lock;
vlc_thread_t thread;
bool stopping;
HANDLE work_event;
} aout_sys_t;
/* MMDeviceLocator IUnknown methods */
static STDMETHODIMP_(ULONG) MMDeviceLocator_AddRef(IActivateAudioInterfaceCompletionHandler *This)
......@@ -257,9 +260,9 @@ static int DeviceSelectLocked(audio_output_t *aout, const char* id)
static int DeviceSelect(audio_output_t *aout, const char* id)
{
aout_sys_t *sys = aout->sys;
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
int ret = DeviceSelectLocked(aout, id);
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
return ret;
}
......@@ -355,12 +358,20 @@ done:
static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
{
aout_sys_t *sys = aout->sys;
if( unlikely( sys->client == NULL ) )
return VLC_EGENERIC;
HRESULT hr;
EnterMTA();
hr = aout_stream_TimeGet(sys->stream, delay);
vlc_mutex_lock(&sys->lock);
if (unlikely(sys->client == NULL))
{
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return -1;
}
hr = aout_stream_owner_TimeGet(sys->stream, delay);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return SUCCEEDED(hr) ? 0 : -1;
......@@ -369,28 +380,37 @@ static int TimeGet(audio_output_t *aout, vlc_tick_t *restrict delay)
static void Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
{
aout_sys_t *sys = aout->sys;
if( unlikely( sys->client == NULL ) )
vlc_mutex_lock(&sys->lock);
if (unlikely(sys->client == NULL))
{
block_Release(block);
vlc_mutex_unlock(&sys->lock);
return;
}
EnterMTA();
HRESULT hr = aout_stream_Play(sys->stream, block, date);
LeaveMTA();
aout_stream_owner_AppendBlock(sys->stream, block, date);
ResetInvalidatedClient(aout, hr);
(void) date;
vlc_mutex_unlock(&sys->lock);
SetEvent(sys->work_event);
}
static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
{
aout_sys_t *sys = aout->sys;
if( unlikely( sys->client == NULL ) )
return;
EnterMTA();
HRESULT hr = aout_stream_Pause(sys->stream, paused);
vlc_mutex_lock(&sys->lock);
if (unlikely(sys->client == NULL))
{
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return;
}
HRESULT hr = aout_stream_owner_Pause(sys->stream, paused);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
(void) date;
......@@ -400,16 +420,81 @@ static void Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
static void Flush(audio_output_t *aout)
{
aout_sys_t *sys = aout->sys;
if( unlikely( sys->client == NULL ) )
return;
EnterMTA();
HRESULT hr = aout_stream_Flush(sys->stream);
vlc_mutex_lock(&sys->lock);
if (unlikely(sys->client == NULL))
{
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return;
}
HRESULT hr = aout_stream_owner_Flush(sys->stream);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
ResetInvalidatedClient(aout, hr);
}
static void *PlaybackThread(void *data)
{
audio_output_t *aout = data;
aout_sys_t *sys = aout->sys;
struct aout_stream_owner *owner = sys->stream;
vlc_thread_set_name("vlc-winstore");
EnterMTA();
vlc_mutex_lock(&sys->lock);
while (true)
{
DWORD ev_count = 1;
HANDLE events[2] = {
sys->work_event,
NULL
};
/* Don't listen to the stream event if the block fifo is empty */
if (sys->stream != NULL && sys->stream->chain != NULL)
events[ev_count++] = owner->buffer_ready_event;
vlc_mutex_unlock(&sys->lock);
WaitForMultipleObjects(ev_count, events, FALSE, INFINITE);
vlc_mutex_lock(&sys->lock);
if (sys->stopping)
break;
if (likely(sys->client != NULL))
{
HRESULT hr = aout_stream_owner_PlayAll(sys->stream);
/* Don't call ResetInvalidatedClient here since this function lock
* the current mutex */
if (unlikely(hr == AUDCLNT_E_DEVICE_INVALIDATED ||
hr == AUDCLNT_E_RESOURCES_INVALIDATED))
{
DeviceSelectLocked(aout, NULL);
if (sys->client == NULL)
{
/* Impossible to recover */
block_ChainRelease(owner->chain);
owner->chain = NULL;
owner->last = &owner->chain;
}
}
}
}
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return NULL;
}
static HRESULT ActivateDevice(void *opaque, REFIID iid, PROPVARIANT *actparms,
void **restrict pv)
{
......@@ -443,13 +528,15 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
aout_sys_t *sys = aout->sys;
HRESULT hr;
aout_stream_t *s = vlc_object_create(aout, sizeof (*s));
if (unlikely(s == NULL))
struct aout_stream_owner *owner =
aout_stream_owner_New(aout, sizeof (*owner), ActivateDevice);
if (unlikely(owner == NULL))
return -1;
aout_stream_t *s = &owner->s;
// Load the "out stream" for the requested device
EnterMTA();
EnterCriticalSection(&sys->lock);
vlc_mutex_lock(&sys->lock);
if (sys->requested_device != NULL)
{
......@@ -459,18 +546,26 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
DeviceRestartLocked(aout);
if (sys->client == NULL)
{
LeaveCriticalSection(&sys->lock);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
vlc_object_delete(&s->obj);
aout_stream_owner_Delete(owner);
return -1;
}
}
}
s->owner.activate = ActivateDevice;
sys->work_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (unlikely(sys->work_event == NULL))
{
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
aout_stream_owner_Delete(owner);
return -1;
}
for (;;)
{
s->owner.device = sys->client;
owner->device = sys->client;
sys->module = vlc_module_load(s, "aout stream", NULL, false,
aout_stream_Start, s, fmt, &hr);
......@@ -538,15 +633,23 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
ISimpleAudioVolume_Release(pc_AudioVolume);
}
LeaveCriticalSection(&sys->lock);
LeaveMTA();
if (sys->module == NULL)
goto error;
assert (sys->stream == NULL);
sys->stream = owner;
sys->stopping = false;
if (vlc_clone(&sys->thread, PlaybackThread, aout))
{
vlc_object_delete(s);
return -1;
aout_stream_owner_Stop(sys->stream);
sys->stream = NULL;
goto error;
}
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
if (sys->client)
{
// the requested device has been used, reset it
......@@ -554,9 +657,14 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
SetRequestedDevice(aout, NULL);
}
assert (sys->stream == NULL);
sys->stream = s;
return 0;
error:
CloseHandle(sys->work_event);
aout_stream_owner_Delete(owner);
vlc_mutex_unlock(&sys->lock);
LeaveMTA();
return -1;
}
static void Stop(audio_output_t *aout)
......@@ -565,11 +673,18 @@ static void Stop(audio_output_t *aout)
assert (sys->stream != NULL);
vlc_mutex_lock(&sys->lock);
sys->stopping = true;
vlc_mutex_unlock(&sys->lock);
SetEvent(sys->work_event);
vlc_join(sys->thread, NULL);
EnterMTA();
aout_stream_Stop(sys->stream);
aout_stream_owner_Stop(sys->stream);
LeaveMTA();
vlc_object_delete(sys->stream);
CloseHandle(sys->work_event);
aout_stream_owner_Delete(sys->stream);
sys->stream = NULL;
}
......@@ -595,7 +710,7 @@ static int Open(vlc_object_t *obj)
free(psz_default);
}
InitializeCriticalSection(&sys->lock);
vlc_mutex_init(&sys->lock);
vlc_sem_init(&sys->async_completed, 0);
sys->refs = 0;
......@@ -633,7 +748,6 @@ static void Close(vlc_object_t *obj)
if (sys->requested_device != sys->default_device)
free(sys->requested_device);
CoTaskMemFree(sys->default_device);
DeleteCriticalSection(&sys->lock);
free(sys);
}
......