@@ -617,9 +617,20 @@ refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
617617
618618int wasapi_stream_reset_default_device (cubeb_stream * stm);
619619
620+ /* Helper for making get_input_buffer work in exclusive mode */
621+ HRESULT get_next_packet_size (cubeb_stream * stm, PUINT32 next)
622+ {
623+ if (stm->input_stream_params .prefs & CUBEB_STREAM_PREF_EXCLUSIVE) {
624+ *next = stm->input_buffer_frame_count ;
625+ return S_OK;
626+ } else {
627+ return stm->capture_client ->GetNextPacketSize (next);
628+ }
629+ }
630+
620631/* This helper grabs all the frames available from a capture client, put them in
621632 * linear_input_buffer. linear_input_buffer should be cleared before the
622- * callback exits. This helper does not work with exclusive mode streams. */
633+ * callback exits. */
623634bool get_input_buffer (cubeb_stream * stm)
624635{
625636 XASSERT (has_input (stm));
@@ -636,9 +647,9 @@ bool get_input_buffer(cubeb_stream * stm)
636647 // single packet each time. However, if we're pulling from the stream we may
637648 // need to grab multiple packets worth of frames that have accumulated (so
638649 // need a loop).
639- for (hr = stm-> capture_client -> GetNextPacketSize ( &next);
650+ for (hr = get_next_packet_size (stm, &next);
640651 next > 0 ;
641- hr = stm-> capture_client -> GetNextPacketSize ( &next)) {
652+ hr = get_next_packet_size (stm, &next)) {
642653 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
643654 // Application can recover from this error. More info
644655 // https://msdn.microsoft.com/en-us/library/windows/desktop/dd316605(v=vs.85).aspx
@@ -705,6 +716,9 @@ bool get_input_buffer(cubeb_stream * stm)
705716 return false ;
706717 }
707718 offset += packet_size;
719+
720+ if (stm->input_stream_params .prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
721+ break ;
708722 }
709723
710724 XASSERT (stm->linear_input_buffer ->length () >= offset);
@@ -1395,8 +1409,11 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
13951409 return CUBEB_ERROR;
13961410 }
13971411
1398- /* The second parameter is for exclusive mode, that we don't use. */
1399- hr = client->GetDevicePeriod (&default_period, NULL );
1412+ if (params.prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
1413+ hr = client->GetDevicePeriod (NULL , &default_period);
1414+ else
1415+ hr = client->GetDevicePeriod (&default_period, NULL );
1416+
14001417 if (FAILED (hr)) {
14011418 LOG (" Could not get device period: %lx" , hr);
14021419 return CUBEB_ERROR;
@@ -1531,7 +1548,7 @@ handle_channel_layout(cubeb_stream * stm, EDataFlow direction, com_heap_ptr<WAV
15311548
15321549 /* Check if wasapi will accept our channel layout request. */
15331550 WAVEFORMATEX * closest;
1534- HRESULT hr = audio_client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED,
1551+ HRESULT hr = audio_client->IsFormatSupported (stream_params-> prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
15351552 mix_format.get (),
15361553 &closest);
15371554 if (hr == S_FALSE) {
@@ -1665,6 +1682,13 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
16651682 // audio according to layout.
16661683 LOG (" Channel count is different from the layout standard!\n " );
16671684 }
1685+
1686+
1687+ if (stream_params->prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
1688+ LOG (" Setup requested=[f=%d r=%u c=%u] mix=[f=%d r=%u c=%u]" ,
1689+ stream_params->format , stream_params->rate , stream_params->channels ,
1690+ mix_params->format , mix_params->rate , mix_params->channels );
1691+ else
16681692 LOG (" Setup requested=[f=%d r=%u c=%u l=%s] mix=[f=%d r=%u c=%u l=%s]" ,
16691693 stream_params->format , stream_params->rate , stream_params->channels ,
16701694 CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout ].name ,
@@ -1681,12 +1705,51 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
16811705 flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
16821706 }
16831707
1684- hr = audio_client->Initialize (AUDCLNT_SHAREMODE_SHARED,
1708+ hr = audio_client->Initialize (stream_params-> prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
16851709 flags,
16861710 frames_to_hns (stm, stm->latency ),
1687- 0 ,
1711+ stream_params-> prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? frames_to_hns (stm, stm-> latency ) : 0 ,
16881712 mix_format.get (),
16891713 NULL );
1714+
1715+ // Try to realign the buffer size
1716+ if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1717+ {
1718+ LOG (" Buffer size misaligned, trying to realign" );
1719+
1720+ audio_client.reset ();
1721+
1722+ hr = device->Activate (__uuidof (IAudioClient),
1723+ CLSCTX_INPROC_SERVER,
1724+ NULL , audio_client.receive_vpp ());
1725+
1726+ if (FAILED (hr)) {
1727+ LOG (" Unable to reactivate audio client for %s: %lx" , DIRECTION_NAME, hr);
1728+ return CUBEB_ERROR;
1729+ }
1730+
1731+ REFERENCE_TIME realigned_time = frames_to_hns (stm, stm->latency ) * *buffer_frame_count / mix_format->nSamplesPerSec + 0.5 ;
1732+
1733+
1734+ hr = audio_client->Initialize (stream_params->prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
1735+ flags,
1736+ realigned_time,
1737+ stream_params->prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? realigned_time : 0 ,
1738+ mix_format.get (),
1739+ NULL );
1740+
1741+ if (FAILED (hr)) {
1742+ LOG (" Unable to initialize realigned audio client for %s: %lx." , DIRECTION_NAME, hr);
1743+ return CUBEB_ERROR;
1744+ }
1745+ }
1746+
1747+ if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT)
1748+ {
1749+ LOG (" The requested format is not supported by the current device." );
1750+ return CUBEB_ERROR_INVALID_FORMAT;
1751+ }
1752+
16901753 if (FAILED (hr)) {
16911754 LOG (" Unable to initialize audio client for %s: %lx." , DIRECTION_NAME, hr);
16921755 return CUBEB_ERROR;
@@ -2244,6 +2307,10 @@ int wasapi_stream_set_volume(cubeb_stream * stm, float volume)
22442307 return CUBEB_ERROR;
22452308 }
22462309
2310+ // Exclusive mode doesn't support setting the volume
2311+ if (stm->output_stream_params .prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
2312+ return CUBEB_ERROR_NOT_SUPPORTED;
2313+
22472314 if (stream_set_volume (stm, volume) != CUBEB_OK) {
22482315 return CUBEB_ERROR;
22492316 }
0 commit comments