1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Copyright (c) 2024. The RigelA open source project team and
 * its contributors reserve all rights.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and limitations under the License.
 */

use std::{
    fmt::{Debug, Formatter},
    future::Future,
    mem::size_of,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll},
};
use windows::Win32::Media::Audio::{
    AudioCategory_SoundEffects,
    XAudio2::XAUDIO2_VOICE_STATE,
    XAudio2::{
        IXAudio2, IXAudio2MasteringVoice, IXAudio2SourceVoice, XAudio2CreateWithVersionInfo,
        XAUDIO2_BUFFER, XAUDIO2_COMMIT_NOW, XAUDIO2_MAX_FREQ_RATIO, XAUDIO2_USE_DEFAULT_PROCESSOR,
        XAUDIO2_VOICE_NOSRC,
    },
    WAVEFORMATEX, WAVE_FORMAT_PCM,
};

#[allow(dead_code)]
pub struct XAudio2OutputStream {
    engine: Arc<IXAudio2>,
    mastering_voice: Arc<IXAudio2MasteringVoice>,
    source_voice: Arc<IXAudio2SourceVoice>,
}

impl XAudio2OutputStream {
    /**
    创建一个音频输出流。
    `sample_rate` 采样率。
    `num_channels` 通道数。
    */
    pub fn new(sample_rate: u32, num_channels: u32) -> Self {
        let mut engine: Option<IXAudio2> = None;
        let mut mastering_voice: Option<IXAudio2MasteringVoice> = None;
        let mut source_voice: Option<IXAudio2SourceVoice> = None;
        unsafe { XAudio2CreateWithVersionInfo(&mut engine, 0, XAUDIO2_USE_DEFAULT_PROCESSOR, 2) }
            .expect("Can't create the XAudio engine.");
        if let Some(x) = engine.as_ref() {
            unsafe {
                x.CreateMasteringVoice(
                    &mut mastering_voice,
                    num_channels,
                    sample_rate,
                    0,
                    None,
                    None,
                    AudioCategory_SoundEffects,
                )
            }
            .expect("Can't create the mastering voice.");
            let block_align = num_channels * 2; // 每个样本的字节数
            let format = WAVEFORMATEX {
                cbSize: size_of::<WAVEFORMATEX>() as u16,
                nChannels: num_channels as u16,
                nSamplesPerSec: sample_rate,
                nBlockAlign: block_align as u16,
                nAvgBytesPerSec: sample_rate * block_align,
                wBitsPerSample: (block_align * 8) as u16,
                wFormatTag: WAVE_FORMAT_PCM as u16,
            };
            unsafe {
                x.CreateSourceVoice(
                    &mut source_voice,
                    &format,
                    XAUDIO2_VOICE_NOSRC,
                    XAUDIO2_MAX_FREQ_RATIO,
                    None,
                    None,
                    None,
                )
            }
            .expect("Can't create the source voice.");
        }
        Self {
            engine: engine.unwrap().into(),
            mastering_voice: mastering_voice.unwrap().into(),
            source_voice: source_voice.unwrap().into(),
        }
    }

    /**
    写入音频数据,并等待播放完毕。
    `data` 音频数据。
    */
    pub async fn write(&self, data: &[u8]) {
        StreamState::new(self.source_voice.clone(), &data).await;
    }

    /**
    从语音队列中删除所有挂起的音频缓冲区。
    */
    #[allow(dead_code)]
    pub fn flush(&self) {
        unsafe { self.source_voice.FlushSourceBuffers() }.unwrap_or(())
    }

    /**
    停止播放。
    */
    pub fn stop(&self) {
        unsafe { self.source_voice.Stop(0, 0) }.expect("Can't stop the stream.");
    }

    /**
    开始播放。
    */
    pub fn start(&self) {
        unsafe { self.source_voice.Start(0, XAUDIO2_COMMIT_NOW) }.expect("Can't start.");
    }
}
impl Debug for XAudio2OutputStream {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "AudioOutputStream")
    }
}
unsafe impl Send for XAudio2OutputStream {}
unsafe impl Sync for XAudio2OutputStream {}
pub struct StreamState(Arc<IXAudio2SourceVoice>);
impl StreamState {
    fn new(source_voice: Arc<IXAudio2SourceVoice>, data: &[u8]) -> Self {
        let mut buf = XAUDIO2_BUFFER::default();
        buf.pAudioData = data.as_ptr();
        buf.AudioBytes = data.len() as u32;
        unsafe { source_voice.SubmitSourceBuffer(&buf, None) }.unwrap_or(());
        Self(source_voice)
    }
}
impl Future for StreamState {
    type Output = ();
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut state = XAUDIO2_VOICE_STATE::default();
        unsafe {
            self.0.GetState(&mut state, 0);
        }
        let p = state.BuffersQueued;
        if p < 1 {
            Poll::Ready(())
        } else {
            cx.waker().wake_by_ref();
            Poll::Pending
        }
    }
}
unsafe impl Send for StreamState {}
unsafe impl Sync for StreamState {}