📄 a2dp_sd_interface_usb.c
字号:
}
if (activity)
/*
USB has signalled to our interface which is a good sign that
it is about to send audio data. Kick the A2DP profile to get
the sink connected ASAP.
*/
MessageSend(getTheAppTask(), APP_KICK_PROFILE_REQ, 0);
}
/*
Process class requests to the Audio Streaming Interface or Endpoint
*/
static void handleAudioStreamingClassRequest(Source req)
{
uint16 packet_size;
bool activity = FALSE;
Sink resp = StreamSinkFromSource(req);
/* Check for outstanding Class requests */
while ((packet_size = SourceBoundary(req)) != 0)
{
/*
Build the response. It must contain the original request,
so copy from the source header.
*/
UsbResponse usbresp;
memcpy(&usbresp.original_request, SourceMapHeader(req), sizeof(UsbRequest));
/* Set the response fields to default values to make the code below simpler */
usbresp.success = TRUE;
usbresp.data_length = 0;
/* Endpoint only allows SET_/GET_ of sampling frequency */
if (((usbresp.original_request.wValue >> 8) == SAMPLING_FREQ_CONTROL) &&
(usbresp.original_request.wLength == 3))
{
if (usbresp.original_request.bRequest == SET_CUR)
{
uint32 new_rate = (uint32)SourceMap(req)[0] |
((uint32)SourceMap(req)[1] << 8) |
((uint32)SourceMap(req)[2] << 16);
/* Reject bad value */
if (new_rate != SAMPLE_RATE)
usbresp.success = FALSE;
}
else if (usbresp.original_request.bRequest == GET_CUR)
{
/* Return current value */
uint8 *ptr = SinkMap(resp) + SinkClaim(resp, 3);
ptr[0] = (uint16)(SAMPLE_RATE & 0xff);
ptr[1] = (uint16)(SAMPLE_RATE >> 8);
ptr[2] = (uint16)(SAMPLE_RATE >> 16); /*lint !e572 !e778 */
usbresp.data_length = 3;
}
else usbresp.success = FALSE;
}
else
usbresp.success = FALSE;
/* Send response */
if (usbresp.data_length)
{
(void)SinkFlushHeader(resp, usbresp.data_length, (void *)&usbresp, sizeof(UsbResponse));
}
else
{
/* Sink packets can never be zero-length, so flush a dummy byte */
(void)SinkClaim(resp, 1);
(void)SinkFlushHeader(resp, 1, (void *)&usbresp, sizeof(UsbResponse));
}
/* Discard the original request */
SourceDrop(req, packet_size);
activity = TRUE;
}
if (activity)
/*
USB has signalled to our interface which is a good sign that
it is about to send audio data. Kick the A2DP profile to get
the sink connected ASAP.
*/
MessageSend(getTheAppTask(), APP_KICK_PROFILE_REQ, 0);
}
/*
Called when a class request could have arrived for
the HID interface.
The USB Host can also communicate to the dongle using
the Feature report defined in the descriptor.
The protcol is made up of GET_REPORT/SET_REPORT pairs
with 8 bytes report payloads.
Host sends SET_REPORT(Feature) with payload:
<request(0x01 to 0xff)> <7 data bytes>
Host issues GET_REPORT(Feature) to read response.
Device responds with:
<response - as in request> <result 0x00=ok, 0x01-0xff=failure> <6 data bytes>
GET_STATE - used to read current device state
Request Payload:
0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Response Payload:
0x01 <result> a2dp_state avrcp_state 0x00 0x00 0x00 0x00
a2dp_state: a2dp_state_initialising = 0
a2dp_state_discovering = 1
a2dp_state_accepting = 2
a2dp_state_initiating = 3
a2dp_state_connected = 4
a2dp_state_streaming = 5
a2dp_state_disconnecting= 6
avrcp_state: avrcp_state_idle = 0
avrcp_state_accepting = 1
avrcp_state_connected = 2
avrcp_state_disconnecting =3
GET_REMOTE_BDADDR - returns the Bluetooth address of the sink
Request Payload:
0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Response Payload:
0x02 <result> nap nap uap lap lap lap
DISCOVER - simulate pressing the devices 'Discover' button
Request Payload:
0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Response Payload:
0x03 <result> 0x00 0x00 0x00 0x00 0x00 0x00
SWITCH_TO_DFU - requests the dongle instantly switches to DFU mode
Request Payload:
0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Response Payload:
None - device will reboot as new USB and hence can't reply
READ_CODEC - returns the current A2DP Codec parameters
Request Payload:
0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Response Payload:
0x05 <result> codec param1 param2 param3 param4 param5
Codec:
1 = SBC: param1=format, param2=bitpool.
*/
static void handleHIDClassRequest(Source req, const a2dpSourceDongleTaskData *theApp)
{
uint16 packet_size;
static uint8 last_request=0;
Sink resp = StreamSinkFromSource(req);
/* Check for outstanding Class requests */
while ((packet_size = SourceBoundary(req)) != 0)
{
/*
Build the response. It must contain the original request,
so copy from the source header.
*/
UsbResponse usbresp;
memcpy(&usbresp.original_request, SourceMapHeader(req), sizeof(UsbRequest));
/* Set the response fields to default values to make the code below simpler */
usbresp.success = FALSE;
usbresp.data_length = 0;
switch (usbresp.original_request.bRequest)
{
/* GET_REPORT */
case 0x01:
{
/* Data phase is min of report and wLength */
uint8 *ptr = SinkMap(resp) + SinkClaim(resp,8);
memset(ptr, 0, 8);
ptr[0] = last_request;
ptr[1] = 0; /* ok */
/* Follow */
switch (last_request)
{
/* Get state */
case 1:
{
ptr[2] = (uint8) theApp->a2dpState; /* A2DP state */
ptr[3] = (uint8) theApp->avrcpState; /* AVRCP state */
}
break;
/* Get remote Bluetooth address */
case 2:
{
ptr[2] = theApp->av_sink_addr.nap >> 8;
ptr[3] = theApp->av_sink_addr.nap & 0xff;
ptr[4] = theApp->av_sink_addr.uap;
ptr[5] = theApp->av_sink_addr.lap >> 16;
ptr[6] = (uint8) theApp->av_sink_addr.lap >> 8;
ptr[7] = theApp->av_sink_addr.lap & 0xff;
}
break;
case 3:
case 4:
/* No specific responses, just return ok */
break;
case 5:
{
ptr[2] = 1; /* SBC */
ptr[3] = 0; /* The app no longer stores this info. */
ptr[4] = 0; /* The app no longer stores this info. */
}
break;
default:
ptr[1] = 1; /* Error */
}
/* 8 byte report returned */
usbresp.data_length = 8;
usbresp.success = TRUE;
}
break;
/* SET_REPORT */
case 0x09:
{
if (usbresp.original_request.wLength == 8)
{
/* Store the request type so we can respond on the GET */
last_request = SourceMap(req)[0];
/* Process command */
if (last_request == 3)
{
/* Initiate discovery */
MessageSend((Task) &theApp->task, APP_DISCOVER_REQ, 0);
}
else if (last_request == 4)
{
/* DFU - switch to boot mode 0 */
BootSetMode(0);
}
usbresp.success = TRUE;
}
}
break;
default:
break;
}
/* Send response */
if (usbresp.data_length)
{
(void) SinkFlushHeader(resp, usbresp.data_length, (uint16 *) &usbresp, sizeof(UsbResponse));
}
else
{
/* Sink packets can never be zero-length, so flush a dummy byte */
(void) SinkClaim(resp, 1);
(void) SinkFlushHeader(resp, 1, (uint16 *) &usbresp, sizeof(UsbResponse));
}
/* Discard the original request */
SourceDrop(req, packet_size);
}
}
/****************************************************************************
NAME
a2dpSdSendHidButton
DESCRIPTION
Presses and releases the specified HID button to simulate a key press.
RETURNS
void
*/
static void a2dpSdSendHidButton(uint8 button)
{
uint8 *ptr;
/* Get the sink */
Sink sink = StreamUsbEndPointSink(end_point_int_out);
/* Button down - copy data into sink and flush it */
(void) SinkClaim(sink, 1);
ptr = SinkMap(sink);
ptr[0] = button;
(void) SinkFlush(sink, 1);
/* Button up - - copy data into sink and flush it */
(void) SinkClaim(sink, 1);
ptr = SinkMap(sink);
ptr[0] = 0x00;
(void) SinkFlush(sink, 1);
}
/****************************************************************************
NAME
a2dpSdHandleButtons
DESCRIPTION
Processes a received button press from the remote end
RETURNS
void
*/
void a2dpSdHandleButtons(avc_operation_id opid, bool state)
{
/* Convert the AVRCP event to HID */
if (!state)
{
if (opid == opid_pause)
{
a2dpSdSendHidButton(HID_PLAYPAUSE);
}
else if (opid == opid_play)
{
a2dpSdSendHidButton(HID_PLAYPAUSE);
}
else if (opid == opid_forward)
{
a2dpSdSendHidButton(HID_TRACK_FORWARD);
}
else if (opid == opid_backward)
{
a2dpSdSendHidButton(HID_TRACK_BACKWARD);
}
else if (opid == opid_stop)
{
a2dpSdSendHidButton(HID_STOP);
}
}
}
/****************************************************************************
NAME
a2dpSdConnectInterfaceToKalimba
DESCRIPTION
Connect Interface Source into Kalimba Sink
RETURNS
void
*/
void a2dpSdConnectInterfaceToKalimba()
{
(void) StreamConnect(PanicNull(StreamUsbEndPointSource(end_point_iso_in)), StreamKalimbaSink(0));
}
/****************************************************************************
NAME
a2dpSdHandleCodecSettingsInd
DESCRIPTION
Not used
RETURNS
void
*/
void a2dpSdHandleCodecSettingsInd(const a2dpSourceDongleTaskData *theApp, uint32 rate)
{
rate = rate;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -