Move hwaddress to raop_start instead of raop_init.
[deb_shairplay.git] / AirTV-Qt / raopservice.cpp
CommitLineData
23e7e3ae
JVH
1/**
2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 */
14
2340bcd3
JVH
15#include "raopservice.h"
16
17#include <QDebug>
18#include <QFile>
19
20static void
21audio_init(void *cls, void **session, int bits, int channels, int samplerate)
22{
23 QMetaObject::invokeMethod((QObject*)cls, "audioInit", Qt::BlockingQueuedConnection,
24 Q_ARG(void*, (void*)session),
25 Q_ARG(int, bits),
26 Q_ARG(int, channels),
27 Q_ARG(int, samplerate));
28}
29
30static void
31audio_set_volume(void *cls, void *session, float volume)
32{
33 QMetaObject::invokeMethod((QObject*)cls, "audioSetVolume", Qt::BlockingQueuedConnection,
34 Q_ARG(void*, session),
35 Q_ARG(float, volume));
36}
37
38static void
39audio_process(void *cls, void *session, const void *buffer, int buflen)
40{
41 QMetaObject::invokeMethod((QObject*)cls, "audioProcess", Qt::BlockingQueuedConnection,
42 Q_ARG(void*, session),
43 Q_ARG(void*, (void*)buffer),
44 Q_ARG(int, buflen));
45}
46
47static void
48audio_flush(void *cls, void *session)
49{
50 QMetaObject::invokeMethod((QObject*)cls, "audioFlush", Qt::BlockingQueuedConnection,
51 Q_ARG(void*, session));
52}
53
54static void
55audio_destroy(void *cls, void *session)
56{
57 QMetaObject::invokeMethod((QObject*)cls, "audioDestroy", Qt::BlockingQueuedConnection,
58 Q_ARG(void*, session));
59}
60
61RaopService::RaopService(QObject *parent) :
62 QObject(parent),
63 m_dnssd(0),
64 m_raop(0)
65{
66 /* This whole hack is required because QAudioOutput
67 * needs to be created in a QThread, threads created
68 * outside Qt are not allowed (they have no eventloop) */
69 m_handler.moveToThread(&m_thread);
70}
71
72RaopService::~RaopService()
73{
74 this->stop();
75
76 dnssd_destroy(m_dnssd);
77 raop_destroy(m_raop);
78}
79
80bool RaopService::init()
81{
82 const char hwaddr[] = { 0x48, 0x5d, 0x60, 0x7c, 0xee, 0x22 };
406e9777 83
2340bcd3
JVH
84 raop_callbacks_t raop_cbs;
85 int error;
86
87 raop_cbs.cls = &m_handler;
88 raop_cbs.audio_init = audio_init;
89 raop_cbs.audio_set_volume = audio_set_volume;
90 raop_cbs.audio_process = audio_process;
91 raop_cbs.audio_flush = audio_flush;
92 raop_cbs.audio_destroy = audio_destroy;
93
94 QFile file("airport.key");
95 if (!file.exists()) {
96 // This is used when running from Qt Creator on Mac
97 file.setFileName("../../../../airport.key");
98 }
99 if (!file.exists()) {
100 // This is used when running from Qt Creator on Windows
101 file.setFileName("../airport.key");
102 }
103 if (!file.exists()) {
104 return false;
105 }
106 file.open(QIODevice::ReadOnly);
107 QByteArray array = file.read(file.size());
108 array.append('\0');
109
406e9777 110 m_raop = raop_init(&raop_cbs, array.data());
2340bcd3
JVH
111 if (!m_raop) {
112 return false;
113 }
114
115 m_dnssd = dnssd_init(hwaddr, sizeof(hwaddr), &error);
116 if (!m_dnssd) {
117 raop_destroy(m_raop);
118 m_raop = NULL;
119 return false;
120 }
121
122 return true;
123}
124
125bool RaopService::start(const QString & name, quint16 port)
126{
406e9777
JVH
127 const char hwaddr[] = { 0x48, 0x5d, 0x60, 0x7c, 0xee, 0x22 };
128
2340bcd3
JVH
129 if (!m_raop || !m_dnssd || m_thread.isRunning()) {
130 return false;
131 }
132
133 m_thread.start();
406e9777 134 if (raop_start(m_raop, &port, hwaddr, sizeof(hwaddr)) < 0) {
2340bcd3
JVH
135 m_thread.quit();
136 m_thread.wait();
137 return false;
138 }
139 if (dnssd_register_raop(m_dnssd, name.toUtf8(), port) < 0) {
140 raop_stop(m_raop);
141 m_thread.quit();
142 m_thread.wait();
143 return false;
144 }
145
146 return true;
147}
148
149void RaopService::stop()
150{
151 if (m_dnssd) {
152 dnssd_unregister_raop(m_dnssd);
153 }
154 if (m_raop) {
155 raop_stop(m_raop);
156 }
157 if (m_thread.isRunning()) {
158 m_thread.quit();
159 m_thread.wait();
160 }
161}
162