Delphi programming blog, зміна гучності windows за допомогою ПДУ

Робота з пультом

Для вирішення першого завдання у нас в якості апаратного забезпечення є ТВ-тюнер Behold TV H6 з пультом дистанційного керування. Для роботи з пультом призначена бібліотека BeholdRC.dll, опис експортованих функцій, а також приклад роботи на Delphi, ми можемо знайти на сайті розробника. Втім, функцій всього кілька. Отримання інформації про натискання клавіш можна реалізувати двома способами, або перевіряти стан за таймером, або використовувати окремий потік. Другий варіант видається більш ефективним і цікавим. Отже реалізований клас матиме ім'я TRemoteVolumeControl, і бути спадкоємцем TThread. На даному етапі розробки, код головної форми відповідатиме за 3 речі:
  1. Створення об'єкта TRemoteVolumeControl при старті додатка
  2. Прийом повідомлень про натисканні кнопок зміни гучності (можливо для поновлення інтерфейсу програми)
  3. Заверешніе потоку, при закритті програми
Для всього цього додамо призначене для користувача повідомлення, процедуру його обробки, і змінну типу TRemoteVolumenControl. Перевизначити конструктор нашого класу-потоку так, щоб в якості параметрів передавати йому дескриптор вікна для приймання повідомлення, і код повідомлення. Надсилаючи звіт про проблеми, WParam буде містити код натиснутої кнопки. Пульти бувають різних модифікацій, з різною кількістю кнопок, що ми опишемо наступним перерахуванням (тип пульта ми отримуємо за допомогою бібліотеки BeholdRC): Для роботи з бібліотекою нам необхідно описати сигнатури експортованих функцій. Всі вони використовують модель викликів cdecl. Алгоритм викликів зазвичай наступний: дізнатися кількість карт, форматувати карту за індексом. Можна отримати її ім'я і тип пульта, опитувати коди натиснутоюклавіші. В кінці роботи необхідно викликати процедуру UnInit. Відразу наведу опис класу TRemoteVolumeControl: Як ми бачимо параметри конструктора класу зберігаються в private члени FNotifyWindow FNotifyMessage. Для ініціалізації роботи з пультом і зміни гучності призначені дві функції InitRemoteControl (пульт) і InitVolumeControl (гучність звуку). При завершенні роботи потоку буде викликаний метод Done. Таким чином, конструктор класу проводить настройку параметрів і ініціалізацію бібліотек. Якщо не вдалося ініціалізувати роботу з пультом, або управління гучністю, то потік завершується. При цьому необхідно видалити посилання на COM-об'єкт управління звуком і закрити бібліотеку пульта. Для роботи з пультом, необхідно завантажити бібліотеку, встановити точки входу в експортовані функції, вибрати пристрій. Відповідний код тривіальний, але нехай буде: В "описі" API бібліотеки сказано, що оптимальний інтервал перевірки стану натиснутоюклавіші 30-50мсек. З цим твердженням я не погоджуся. Практичні досліди показують, що натискання на кнопку і її відпускання займає приблизно 150-200мс, що дуже добре демонструється натисканням кнопки відключення звуку Mute (при інтервалі опитування в 50 мс, звук включається-вимикається 2-3 рази). Основний робочий цикл програми дуже простий: опитати стан пульта (getRemoteCode), якщо натиснута кнопка (код відмінний від $ FF), то зробити необхідні маніпуляції (процедура RCKeyPress), відправитися в сон на 180мс до наступної перевірки. Необхідні маніпуляції в даному випадку це сповістити головну форму додатку, і змінити гучність. Але поки що ми не розглядаємо деталі. Як бачимо, робота з пультом досить проста.

управління звуком

Взагалі я ні разу не замислювався про те як змінювати гучність звуку в системі. Тому вирушив вивчати документацію. Втім в деталі зовсім не вдавався. Наскільки я зрозумів, починаючи з Windows Vista, методи управління звуком кардинально змінилися. Про це нам розповідає розділ MSDN Core Audio API. Управляти звуком ми можемо на глобальному рівні, або змінюючи тільки свій звуковий потік. Нас цікавить перший варіант. Для роботи нам будуть потрібні кілька інтерфейсів: IMMDeviceEnumerator, представляє колекцію мультимедіа пристроїв; IMMDevice представляє однієї пристрій, і інтерфейс IAudioEndpointVolume для управління гучністю. На жаль Delphi не містить опису інтерфейсів, тому треба буде переписати заголовки mmDeviceApi.h EndpointVolume.h (результат прикріплений в кінці статті). В гуглі ви можете знайти файл mmDevApi.pas з описом інтерфейсів на Delphi, але там описані тільки ті інтерфейси, що потрібні для зміни гучності, а не повністю відповідають заголовки. Варто зазначити, що використовуючи ці інтерфейси ми можемо не тільки керувати гучністю, а й отримувати повідомлення про те, що гучність була змінена (IAudioEndpointVolumeCallback). Тепер якщо бути коротким, то наша функція InitVolumeControl повинна отримати посилання на інтерфейс IAudioEndpointVolume, що ми і зробимо: Тепер ми можемо описати функцію RCKeyPress. По-перше ми повідомляємо форму про самій клавіші, відправляючи їй її код. Далі в залежності від натиснутоюклавіші ми або збільшуємо / зменшуємо гучність (VolumeStepUp / VolumeStepDown). При натисканні на кнопку mute, ми повинні визначити поточний стан і інвертувати його. Натиснувши на кнопку вимикання ми можемо відправити формі повідомлення WM_CLOSE, хоча ми її вже повідомили про це відправивши код кнопки. Тепер наше додаток може змінювати загальну гучність звуку в Window Vista 7. Хотілося б реалізувати який-небудь гарний інтерфейс для цього, з прозорою формою і малюнком динаміка, але я на знаю як таке зробити в Direct2D. бо зіткнувся з проблемою в минулий раз. Вихідний код описуваного класу, а також файли опису інтерфейсів MMDeviceAPI і EndpointVolume можна скачати тут.