123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- #include "../Winamp/OUT.H"
- #include "api.h"
- #include "resource.h"
- #include <Mmdeviceapi.h>
- #include <Audioclient.h>
- #include <Audiosessiontypes.h>
- #include "../winamp/wa_ipc.h"
- #include <api/service/waServiceFactory.h>
- #include <strsafe.h>
- #define WASAPI_PLUGIN_VERSION L"0.3"
- constexpr auto VolumeLevelMultiplier = 255;
- static wchar_t plugin_name[256];
- // wasabi based services for localisation support
- api_service *WASABI_API_SVC = 0;
- api_language *WASABI_API_LNG = 0;
- HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
- static const UINT32 REFTIMES_PER_SEC = 10000000;
- static const UINT32 REFTIMES_PER_MILLISEC = 10000;
- // TODO(benski) is there some library that has this
- static const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
- static const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
- static const IID IID_IAudioClient = __uuidof(IAudioClient);
- static const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
- static const IID IID_IAudioClock = __uuidof(IAudioClock);
- static bool InitializedCOM;
- extern Out_Module plugin;
- static IAudioClient *client=0;
- static IAudioRenderClient *render_client=0;
- static IAudioClock *clock=0;
- static ISimpleAudioVolume *audio_volume = 0;
- static IChannelAudioVolume *channel_volume = 0;
- static UINT32 bufferFrameCount;
- static WORD bytes_per_frame;
- static UINT64 frequency=0;
- static UINT32 sample_rate;
- static double start_time_ms = 0;
- static bool paused=false;
- static float start_volume = 1.0;
- static float start_pan = 0;
- WAVEFORMATEXTENSIBLE WaveFormatForParameters(int samplerate, int numchannels, int bitspersamp);
- static void SetVolume(int volume);
- static void SetPan(int pan);
- static CRITICAL_SECTION ThreadSync;
- static void Config(HWND hwndParent)
- {
- }
- static int DoAboutMessageBox(HWND parent, wchar_t* title, wchar_t* message)
- {
- MSGBOXPARAMSW msgbx = {sizeof(MSGBOXPARAMSW),0};
- msgbx.lpszText = message;
- msgbx.lpszCaption = title;
- msgbx.lpszIcon = MAKEINTRESOURCEW(102);
- msgbx.hInstance = GetModuleHandle(0);
- msgbx.dwStyle = MB_USERICON;
- msgbx.hwndOwner = parent;
- return MessageBoxIndirectW(&msgbx);
- }
- static void About(HWND hwndParent)
- {
- wchar_t message[1024], text[1024] =L"";
- WASABI_API_LNGSTRINGW_BUF(IDS_NULLSOFT_WASAPI_OLD,text,1024);
- StringCchPrintfW(message, 1024, WASABI_API_LNGSTRINGW(IDS_ABOUT_TEXT),
- plugin.description, TEXT(__DATE__));
- DoAboutMessageBox(hwndParent,text,message);
- }
- static void Init()
- {
- /*
- HRESULT hr;
- hr=CoInitializeEx(0, COINIT_MULTITHREADED);
- if (SUCCEEDED(hr)) {
- InitializedCOM = true;
- } else {
- InitializedCOM = false;
- }
- */
- // loader so that we can get the localisation service api for use
- WASABI_API_SVC = (api_service*)SendMessage(plugin.hMainWindow, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
- if (WASABI_API_SVC == (api_service*)1) WASABI_API_SVC = NULL;
- waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
- if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
- // need to have this initialised before we try to do anything with localisation features
- WASABI_API_START_LANG(plugin.hDllInstance,OutWasapiLangGUID);
- StringCbPrintfW(plugin_name,sizeof(plugin_name),WASABI_API_LNGSTRINGW(IDS_NULLSOFT_WASAPI), WASAPI_PLUGIN_VERSION);
- plugin.description = (char *)plugin_name;
- }
- static void Quit()
- {
- /*
- if (InitializedCOM) {
- CoUninitialize();
- }*/
- }
- static int Open(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms)
- {
-
- CoInitialize(0);
- IMMDeviceEnumerator *enumerator=0;
- IMMDevice *device=0;
- sample_rate = samplerate;
- HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enumerator);
- hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &device);
- hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&client);
- if (FAILED(hr)) {
- wchar_t temp[1234];
- wsprintf(temp, L"device->Activate: %x", hr);
- ::MessageBox(NULL, temp, L"error", MB_OK);
- return -1;
- }
- WAVEFORMATEXTENSIBLE wave_format = WaveFormatForParameters(samplerate, numchannels, bitspersamp);
- bytes_per_frame = wave_format.Format.nBlockAlign;
- hr = client->Initialize(
- AUDCLNT_SHAREMODE_SHARED,
- 0x80000000,
- 1 * REFTIMES_PER_SEC,
- 0,
- (WAVEFORMATEX *)&wave_format,
- NULL);
- if (FAILED(hr)) {
- wchar_t temp[1234];
- wsprintf(temp, L"client->Initialize: %x", hr);
- ::MessageBox(NULL, temp, L"error", MB_OK);
- return -1;
- }
- // Get the actual size of the allocated buffer.
- hr = client->GetBufferSize(&bufferFrameCount);
- if (FAILED(hr)) {
- wchar_t temp[1234];
- wsprintf(temp, L"client->GetBufferSize: %x", hr);
- ::MessageBox(NULL, temp, L"error", MB_OK);
- return -1;
- }
- hr = client->GetService(
- IID_IAudioRenderClient,
- (void**)&render_client);
- if (FAILED(hr)) {
- wchar_t temp[1234];
- wsprintf(temp, L"client->GetService(IID_IAudioRenderClient): %x", hr);
- ::MessageBox(NULL, temp, L"error", MB_OK);
- return -1;
- }
- hr = client->GetService(
- IID_IAudioClock,
- (void**)&clock);
- if (FAILED(hr)) {
- wchar_t temp[1234];
- wsprintf(temp, L"client->GetService(IID_IAudioClock): %x", hr);
- ::MessageBox(NULL, temp, L"error", MB_OK);
- return -1;
- }
- hr = clock->GetFrequency(&frequency);
- hr = client->GetService(__uuidof(ISimpleAudioVolume), reinterpret_cast<void **>( & audio_volume));
- hr = client->GetService(__uuidof(IChannelAudioVolume), (void **)&channel_volume);
- start_time_ms = 0;
- paused=false;
- client->Start();
- // Start volume is in range 0.0 to 1.0, should be converted
- SetVolume((int)(start_volume * VolumeLevelMultiplier));
-
- SetPan((int)start_pan);
-
- return 1000;
- }
- static void Close()
- {
-
- if (client) {
- client->Stop();
- client->Release();
- client=0;
- }
- if (render_client) {
- render_client->Release();
- render_client=0;
- }
- if (clock) {
- clock->Release();
- clock=0;
- }
- if (audio_volume) {
- audio_volume->Release();
- audio_volume=0;
- }
- if (channel_volume) {
- channel_volume->Release();
- channel_volume=0;
- }
-
- }
- static int CanWrite()
- {
- if (client) {
- UINT32 numFramesPadding;
- HRESULT hr = client->GetCurrentPadding(&numFramesPadding);
- return (bufferFrameCount - numFramesPadding) * bytes_per_frame;
- }
- else {
- return 0;
- }
- }
- static int Write(char* buf, int len)
- {
-
- if (!render_client)
- {
- return -1;
- }
- else
- {
- int LenghtToWrite = CanWrite();
- if (LenghtToWrite > 0 && LenghtToWrite >= len)
- {
- BYTE* data;
- render_client->GetBuffer(len / bytes_per_frame, &data);
- memcpy(data, buf, len);
- render_client->ReleaseBuffer(len / bytes_per_frame, 0);
- }
- }
- return 0;
-
- }
- static int IsPlaying()
- {
- return CanWrite() == 0;
- }
- static int Pause(int pause)
- {
-
-
- int old_paused = paused?1:0;
- if (client) {
- if (pause) {
- client->Stop();
- paused=true;
- } else {
- client->Start();
- paused=false;
- }
- }
-
- return old_paused;
- }
- static void SetVolume(int volume)
- {
-
-
- float fVolume = (float)volume / (float)VolumeLevelMultiplier;
- if (volume >= 0) {
- start_volume = fVolume;
- if (audio_volume) {
- audio_volume->SetMasterVolume(fVolume, 0);
- }
- }
-
- }
- static void SetPan(int pan)
- {
-
-
- float fPan = (float)pan/128.0f;
- if (channel_volume) {
- start_pan = fPan;
- if (fPan < 0) {
- channel_volume->SetChannelVolume(0, 1.0f, NULL);
- channel_volume->SetChannelVolume(1, 1.0f-fPan, NULL);
- } else if (fPan > 0) {
- channel_volume->SetChannelVolume(1, 1.0f, NULL);
- channel_volume->SetChannelVolume(0, 1.0f-fPan, NULL);
- }
- }
-
- }
- static void Flush(int t)
- {
-
-
- if (client) {
- client->Stop();
- client->Reset();
- start_time_ms = t;
- client->Start();
- }
-
- }
- static double GetOutputTimeAsDouble()
- {
-
-
- if (clock) {
- UINT64 position;
- HRESULT hr = clock->GetPosition(&position, NULL);
- double output_time = (double)position * 1000.0 / (double)frequency;
-
- return output_time + start_time_ms;
- } else {
-
- return 0;
- }
- }
- static int GetOutputTime()
- {
- return (int)GetOutputTimeAsDouble();
- }
- static int GetWrittenTime()
- {
- double time_in_buffer = (1000.0 * (double)CanWrite()) / ((double)bytes_per_frame * (double)sample_rate);
- return (int)(GetOutputTimeAsDouble() + time_in_buffer);
- }
- Out_Module plugin = {
- OUT_VER_U,
- 0,
- 70,
- NULL,
- NULL,
- Config,
- About,
- Init,
- Quit,
- Open,
- Close,
- Write,
- CanWrite,
- IsPlaying,
- Pause,
- SetVolume,
- SetPan,
- Flush,
- GetOutputTime,
- GetWrittenTime,
- };
- extern "C" {
- __declspec(dllexport) int __cdecl winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param)
- {
- return OUT_PLUGIN_UNINSTALL_REBOOT;
- }
- __declspec(dllexport) Out_Module * __cdecl winampGetOutModule(){ return &plugin; }
- __declspec(dllexport) void __cdecl winampGetOutModeChange(int mode)
- {
- }
- }
|