@@ -524,9 +524,20 @@ refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
524524
525525int wasapi_stream_reset_default_device (cubeb_stream * stm);
526526
527+ /* Helper for making get_input_buffer work in exclusive mode */
528+ HRESULT get_next_packet_size (cubeb_stream * stm, PUINT32 next)
529+ {
530+ if (stm->input_stream_params .prefs & CUBEB_STREAM_PREF_EXCLUSIVE) {
531+ *next = stm->input_buffer_frame_count ;
532+ return S_OK;
533+ } else {
534+ return stm->capture_client ->GetNextPacketSize (next);
535+ }
536+ }
537+
527538/* This helper grabs all the frames available from a capture client, put them in
528539 * linear_input_buffer. linear_input_buffer should be cleared before the
529- * callback exits. This helper does not work with exclusive mode streams. */
540+ * callback exits. */
530541bool get_input_buffer (cubeb_stream * stm)
531542{
532543 XASSERT (has_input (stm));
@@ -543,9 +554,9 @@ bool get_input_buffer(cubeb_stream * stm)
543554 // single packet each time. However, if we're pulling from the stream we may
544555 // need to grab multiple packets worth of frames that have accumulated (so
545556 // need a loop).
546- for (hr = stm-> capture_client -> GetNextPacketSize ( &next);
557+ for (hr = get_next_packet_size (stm, &next);
547558 next > 0 ;
548- hr = stm-> capture_client -> GetNextPacketSize ( &next)) {
559+ hr = get_next_packet_size (stm, &next)) {
549560 if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
550561 // Application can recover from this error. More info
551562 // https://msdn.microsoft.com/en-us/library/windows/desktop/dd316605(v=vs.85).aspx
@@ -619,7 +630,11 @@ bool get_input_buffer(cubeb_stream * stm)
619630 LOG (" FAILED to release intput buffer" );
620631 return false ;
621632 }
622- offset += input_stream_samples;
633+
634+ offset += input_stream_samples;
635+
636+ if (stm->input_stream_params .prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
637+ break ;
623638 }
624639
625640 XASSERT (stm->linear_input_buffer ->length () >= offset);
@@ -1297,9 +1312,13 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
12971312 return CUBEB_ERROR;
12981313 }
12991314
1300- /* The second parameter is for exclusive mode, that we don't use. */
13011315 REFERENCE_TIME default_period;
1302- hr = client->GetDevicePeriod (&default_period, NULL );
1316+
1317+ if (params.prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
1318+ hr = client->GetDevicePeriod (NULL , &default_period);
1319+ else
1320+ hr = client->GetDevicePeriod (&default_period, NULL );
1321+
13031322 if (FAILED (hr)) {
13041323 LOG (" Could not get device period: %lx" , hr);
13051324 return CUBEB_ERROR;
@@ -1391,7 +1410,7 @@ handle_channel_layout(cubeb_stream * stm, EDataFlow direction, com_heap_ptr<WAV
13911410
13921411 /* Check if wasapi will accept our channel layout request. */
13931412 WAVEFORMATEX * closest;
1394- HRESULT hr = audio_client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED,
1413+ HRESULT hr = audio_client->IsFormatSupported (stream_params-> prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
13951414 mix_format.get (),
13961415 &closest);
13971416 if (hr == S_FALSE) {
@@ -1518,11 +1537,27 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
15181537 mix_params->channels = mix_format->nChannels ;
15191538 mix_params->layout = mask_to_channel_layout (mix_format.get ());
15201539
1521- LOG (" Setup requested=[f=%d r=%u c=%u l=%u] mix=[f=%d r=%u c=%u l=%u]" ,
1522- stream_params->format , stream_params->rate , stream_params->channels ,
1523- stream_params->layout ,
1524- mix_params->format , mix_params->rate , mix_params->channels ,
1525- mix_params->layout );
1540+ if (mix_params->layout == CUBEB_LAYOUT_UNDEFINED) {
1541+ LOG (" Stream using undefined layout! Any mixing may be unpredictable!\n " );
1542+ } else if (mix_format->nChannels != mix_params->channels ) {
1543+ // The CUBEB_CHANNEL_LAYOUT_MAPS[mix_params->layout].channels may be
1544+ // different from the mix_params->channels. 6 channel ouput with stereo
1545+ // layout is acceptable in Windows. If this happens, it should not downmix
1546+ // audio according to layout.
1547+ LOG (" Channel count is different from the layout standard!\n " );
1548+ }
1549+
1550+
1551+ if (stream_params->prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
1552+ LOG (" Setup requested=[f=%d r=%u c=%u] mix=[f=%d r=%u c=%u]" ,
1553+ stream_params->format , stream_params->rate , stream_params->channels ,
1554+ mix_params->format , mix_params->rate , mix_params->channels );
1555+ else
1556+ LOG (" Setup requested=[f=%d r=%u c=%u l=%u] mix=[f=%d r=%u c=%u l=%u]" ,
1557+ stream_params->format , stream_params->rate , stream_params->channels ,
1558+ stream_params->layout ,
1559+ mix_params->format , mix_params->rate , mix_params->channels ,
1560+ mix_params->layout );
15261561
15271562 DWORD flags = AUDCLNT_STREAMFLAGS_NOPERSIST;
15281563
@@ -1534,12 +1569,51 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
15341569 flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
15351570 }
15361571
1537- hr = audio_client->Initialize (AUDCLNT_SHAREMODE_SHARED,
1572+ hr = audio_client->Initialize (stream_params-> prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
15381573 flags,
15391574 frames_to_hns (stm, stm->latency ),
1540- 0 ,
1575+ stream_params-> prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? frames_to_hns (stm, stm-> latency ) : 0 ,
15411576 mix_format.get (),
15421577 NULL );
1578+
1579+ // Try to realign the buffer size
1580+ if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1581+ {
1582+ LOG (" Buffer size misaligned, trying to realign" );
1583+
1584+ audio_client.reset ();
1585+
1586+ hr = device->Activate (__uuidof (IAudioClient),
1587+ CLSCTX_INPROC_SERVER,
1588+ NULL , audio_client.receive_vpp ());
1589+
1590+ if (FAILED (hr)) {
1591+ LOG (" Unable to reactivate audio client for %s: %lx" , DIRECTION_NAME, hr);
1592+ return CUBEB_ERROR;
1593+ }
1594+
1595+ REFERENCE_TIME realigned_time = frames_to_hns (stm, stm->latency ) * *buffer_frame_count / mix_format->nSamplesPerSec + 0.5 ;
1596+
1597+
1598+ hr = audio_client->Initialize (stream_params->prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED,
1599+ flags,
1600+ realigned_time,
1601+ stream_params->prefs & CUBEB_STREAM_PREF_EXCLUSIVE ? realigned_time : 0 ,
1602+ mix_format.get (),
1603+ NULL );
1604+
1605+ if (FAILED (hr)) {
1606+ LOG (" Unable to initialize realigned audio client for %s: %lx." , DIRECTION_NAME, hr);
1607+ return CUBEB_ERROR;
1608+ }
1609+ }
1610+
1611+ if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT)
1612+ {
1613+ LOG (" The requested format is not supported by the current device." );
1614+ return CUBEB_ERROR_INVALID_FORMAT;
1615+ }
1616+
15431617 if (FAILED (hr)) {
15441618 LOG (" Unable to initialize audio client for %s: %lx." , DIRECTION_NAME, hr);
15451619 return CUBEB_ERROR;
@@ -2105,6 +2179,10 @@ int wasapi_stream_set_volume(cubeb_stream * stm, float volume)
21052179 return CUBEB_ERROR;
21062180 }
21072181
2182+ // Exclusive mode doesn't support setting the volume
2183+ if (stm->output_stream_params .prefs & CUBEB_STREAM_PREF_EXCLUSIVE)
2184+ return CUBEB_ERROR_NOT_SUPPORTED;
2185+
21082186 if (stream_set_volume (stm, volume) != CUBEB_OK) {
21092187 return CUBEB_ERROR;
21102188 }
0 commit comments