Сервери та потоки

Для відтворення звуку за допомогою NAS необхідно мати підключення до сервера і організувати на цьому серверіпотікПотік це обробний звук конвеєр, за допомогою якого дані передаються від джерела до одержувача C допомогою потоків можна різними способами комбінувати дані, що надходять з декількох джерел

Лістинг 83 Приватні члени класу NasPlayer

private:

AuServer *_server AuFlowID _flow

Метод Play спочатку встановлює зєднання з сервером, що включає в себе формування і реєстрацію потоку B NAS всі потоки при створенні перебувають у стані паузи Як тільки потік буде виведений зі стану паузи, сервер почне запитувати аудіодані Зауважимо, що в системі NAS завдання контролю за подвійний буферизацією покладена на сервер, клієнтська частина просто відповідає на запити, передаючи серверу дані Всі перераховані нижче функції типу AuXxxx відносяться до бібліотеці NAS

Лістинг 84 Реалізація класу NasPlayer

void NasPlayer::Play(){

OpenServer () / / Встановлюємо звязок

/ / З сервером

InitializeQueue (128 * 1024L) / / Ініціалізація черги

/ / Завдовжки 128 Кб

AuStartFlow (_server, _flow, NULL) / / Запускаємо потік

while ( _finished) {/ / Затримуємо повідомлення до тих

/ / Пір, поки відтворення не

/ / Буде закінчено

AuEvent ev

AuNextEvent(_server, AuTrue, &ampev) AuDispatchEvent(_server, &ampev)

}

AuCloseServer (_server) / / Закриваємо підключення

/ / До сервера

}

Виклик підсистем та повідомлення

Всякий раз, коли аудіосервер вимагається наступна порція даних, він пересилає клієнту повідомлення Метод Play, o якому ми розповідали вище, для обробки цих повідомлень використовує бібліотечну функцію AuDispatchEvent Ця функція викликає функцію зворотного виклику Якщо функція зворотного виклику отримуєуведомляющее(notify)  повідомлення,вона активізує метод Notify, який інтерпретує повідомлення, і ініціалізує SendData для пересилання на сервер даних відповідно із запитом

Лістинг 83 Приватні члени класу NasPlayer (продовження)

private:

void OpenServer () / / Підключення до сервера friend AuBool NasEventHandler (AuServer * server,

AuEvent *event, AuEventHandlerRec *eventData) AuBool Notify(AuElementNotifyEvent *notifyEvent)

void SendData(AuUint32 numBytes)

B кожному запиті від сервера NAS вказується, який обсяг даних потрібно передати серверу Сервер вимагає до себе особливо уважного ставлення:

клієнтська частина повинна надати саме той обсяг даних, який був затребуваний Оскільки витребувані дані можуть перебувати в черзі «в розбивку», я копіюю дані з черги в допоміжний буфер, а потім переписую цей буфер на сервер

.

Лістинг 83 Приватні члени класу NasPlayer (продовження)

private:

#define nasBufferSize 100000

Sample16 _buffer[nasBufferSize]

Бібліотечна функція AuDispatchEvent пересилає повідомлення функції зворотного виклику Функція OpenServer реєструє функцію NasEventHandler в якості функції зворотного виклику, яка буде обробляти повідомлення Таким чином, кожен раз, коли аудиопоток потребує поповнення даних, сервер посилає повідомлення, яке врешті-решт доходить до функції NasEventHandler

Основне завдання цієї функції перетворити виклик функції в активізацію методу Вона використовує для зберігання покажчика на обєкт класу NasPlayer поле даних користувача і запускає метод Notify для обробки повідомлення

Лістинг 84 Реалізація класу NasPlayer (продовження)

AuBool NasEventHandler (AuServer *, / / ​​He використовується

AuEvent *event, AuEventHandlerRec *eventData)

{

NasPlayer *me = reinterpret_cast&ltNasPlayer *&gt(eventData &gt

data)

switch (event-&gttype) {

case AuEventTypeElementNotify:

return me-&gtNotify(reinterpret_cast&ltAuElementNotifyEvent

* &gt(event))

default: / / Відбулося якесь

/ / Інше подія

break

}

return AuTrue

}

Для ідентифікації події потрібно багаторівнева класифікація Перший рівень цеmun  повідомлення, що аналізується функцією NasEventHandler Метод Notify обробляє повідомлення уведомляющего типу, класифікуючи їх відповідно довидомповідомлення тапричиною,викликає повідомлення такого виду Тут треба виділити дві важливі події: перше коли кількість даних на сервері досягає мінімальної позначки, і друге коли сервер змушений перервати висновок через відсутність даних у буфері B результаті цих подій відбувається звернення до функції SendData для отримання додаткової порції даних і пересилання їх на сервер

Зауважимо, що в разі нормального функціонування сервера повідомлення про перерву в роботі надходити не повинні Однак при налагодженні програми ви

зіткнетеся з великою кількістю пауз при виведенні, які обумовлені тим,

що при зупинці виконання програми сервер продовжує працювати

Якщо велика кількість пауз виникає при нормальній роботі, то, можливо, вам потрібно збільшити розмір буфера і підвищити значення мінімального рівня даних

Лістинг 84 Реалізація класу NasPlayer (продовження)

AuBool NasPlayer::Notify(AuElementNotifyEvent *notifyEvent) {

switch (notifyEvent-&gtkind) {

case AuElementNotifyKindLowWater: / / Досягнуто мінімальний

/ / Рівень

SendData (notifyEvent-> num_bytes) / / Переслати

/ / Додаткові дані

break

case AuElementNotifyKindState:

/ / Робота сервера перервана

/ / Через нестачу даних

if ( (notifyEvent-&gtcur_state == AuStatePause)

&amp&amp(notifyEvent-&gtreason == AuReasonUnderrun)) SendData(notifyEvent-&gtnum_bytes)

else / / Будь-яке інше зміна

/ / Статусу: просто

/ / Закінчуємо

_finished = true

break

}

return AuTrue

}

Передача даних на сервер проблем не викликає Потрібно просто витягти дані з черги і передати їх серверу Складність тільки одна: сервер повідомляє, скільки йому потрібно байтів, а не відліків Також врахуйте, що, на відміну від операційних систем Windows і Mac OS, чергу перезаполнять відразу, а не в какомлибо іншому потоці виконання програми

Лістинг 84 Реалізація класу NasPlayer (продовження)

void NasPlayer::SendData(AuUint32 numBytes){

unsigned long bytesRead

= FromQueue(_buffer,numBytes/sizeof(Sample16))

* sizeof(Sample16)

bool allDone = ((bytesRead &lt numBytes) &amp&amp _endOfSource) AuWriteElement(_server, _flow, 0, bytesRead, _buffer,

allDone, NULL)

FillQueue()

}

Сервер NAS не використовує збережену окремо інформацію про розрядності і форматі даних Навпаки, для відображення обох параметрів застосовується єдиний код Сервер може сприймати дані, записані за допомогою різних типів ІКМ, а поряд з ними і дані декількох форматів, що використовують

компресію (He забувайте, що сервер може бути запущений на іншій машині, що використовує інший порядок проходження байтів, тому необхідно вказувати, де знаходиться молодший розряд LSB, а де старший MSB) Ця функція перетворює інформацію про розрядності відліку в підходящий код сервера Я також тестую порядок проходження байтів на локальній машині, що дозволяє повідомити сервер, в якому форматі будуть записані надходять 16-розрядні вибірки

Дана функція написана в припущенні, що short це 16-бітний це-

лочісленний формат Bo багатьох сучасних компютерах так воно і є

Лістинг 84 Реалізація класу NasPlayer (продовження)

unsigned char NasFormatCode(int sampleBits)

{

if (sampleBits == 8)

return AuFormatLinearSigned8

int lsb = 0 / / За замовчуванням: формат MSB

{/ / Перевірка внутрішнього формату

/ / Системи на відповідність формату LSB

union {short int sixteen / / 16-бітове значення

struct {char a, b } Eight / / Два байти

} lsbTest

lsbTestsixteen = 1 / / Задаємо молодший байт,

/ / Відкидаємо старший

if (lsbTesteighta) {lsb = 1 } / / Перевіряємо перший байт

}

if (lsb) return AuFormatLinearSigned16LSB

else return AuFormatLinearSigned16MSB

}

Джерело: Кінтцель Т Керівництво програміста по роботі зі звуком = A Programmers Guide to Sound: Пер з англ М: ДМК Пресс, 2000 432 с, іл (Серія «Для програмістів»)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*