Перенаправление аудио потока в блю туф устройство

зубок александр
Дата: 23.05.2015 18:25:01
Кто нибудь может подсказать данный вопрос.
Инфы в инете мало есть код с мсдн но как том мало помогает.

Сама связь между смартом (вообще тип уст-ва не важен) и компом есть.

Но вот аудипоток с хэдсета на телефон не удается перенаправить. Речь идет о разработке драйвера хандсфри.
Будет работать с определенным софтом. Инстументарий - vs2013, win 8.1, windbg x64 - отладчик. сам драйвер и софт крутятся на виртуальной машине x64 с win 8.1

Разработка только на чистом с и вин апи без вариантов.

Вот код с мсдна

MyTraceFunc(0, TRACE_LEVEL_INFORMATION, DBG_CONNECT, "%s:%s@%d Indication:0x%x\n", __FUNCTION__, __FILE__, __LINE__, Indication);
    switch(Indication)
    {
		case ScoIndicationAddReference:
		case ScoIndicationReleaseReference:
            break;
		case ScoIndicationRemoteConnect:
        {
			PEBTH_SERVER_CONTEXT devCtx = (PEBTH_SERVER_CONTEXT)Context;
// тут отрабатывает при исходящем и входящем звонках
			EBthSrvSendConnectResponse(devCtx, Parameters);
            break;
        }
		case ScoIndicationRemoteDisconnect:
        {
            //
            // We register EBthSrvConnectionIndicationCallback for disconnect
            //
            //NT_ASSERT(FALSE);
            break;
        }
        //case IndicationRemoteConfigRequest:
        //case IndicationRemoteConfigResponse:
        //case IndicationFreeExtraOptions:
            break;
    }


Далее сама функция - по сути наполнение BRB структуры и все пассы с ней

brb = (struct _BRB_SCO_OPEN_CHANNEL*) &(connection->ConnectDisconnectBrb);
	DevCtx->Header.ProfileDrvInterface.BthReuseBrb((PBRB)brb, BRB_SCO_OPEN_CHANNEL_RESPONSE);

    brb->Hdr.ClientContext[0] = connectionObject;
    brb->BtAddress = ConnectParams->BtAddress;
    
	brb->TransmitBandwidth = 8000;
	brb->ReceiveBandwidth = 8000;
	brb->MaxLatency = 0xffff;
	brb->PacketType = SCO_HV1 | SCO_HV3 | SCO_EV3; // SCO_PKT_ALL;
	brb->ContentFormat = SCO_VS_SETTING_DEFAULT; //SCO_VS_IN_CODING_LINEAR | SCO_VS_IN_SAMPLE_SIZE_8BIT | SCO_VS_AIR_CODING_FORMAT_CVSD;
	//brb->Reserved = ;
	brb->RetransmissionEffort = SCO_RETRANSMISSION_NONE;

	brb->ChannelHandle = ConnectParams->ConnectionHandle;
	brb->Response = SCO_CONNECT_RSP_RESPONSE_SUCCESS;

	brb->ChannelFlags = SCO_CF_LINK_SUPPRESS_PIN | SCO_CF_LINK_AUTHENTICATED;
    
    //
    // Get notifications about disconnect
    //
    brb->CallbackFlags = CALLBACK_DISCONNECT;
	brb->Callback = &EBthSrvConnectionIndicationCallback;
    brb->CallbackContext = connectionObject;
    brb->ReferenceObject = (PVOID) WdfDeviceWdmGetDeviceObject(DevCtx->Header.Device);

	status = EBthSharedSendBrbAsync(
        DevCtx->Header.IoTarget,
        connection->ConnectDisconnectRequest,
        (PBRB) brb,
        sizeof(*brb),
		EBthSrvRemoteConnectResponseCompletion,
        brb
        );


тут цепляю коллбэк функцию которая по логике должна отрабатывать по факту начала разговора
status = EBthSrvConnectionStateConnected(connectionObject);


EBthSrvConnectionStateConnected(
    WDFOBJECT ConnectionObject
    )
/*++
Routine Description:

    This routine is invoked by EBthSrvRemoteConnectResponseCompletion
    when connect response is completed.

    We initialize and submit continous readers in this routine.

Arguments:

    ConnectionObject - Connection object for which connect response completed

--*/
{
	PEBTH_CONNECTION connection;
	NTSTATUS status = STATUS_SUCCESS;

	TRACEFUNC();

	connection = GetConnectionObjectContext(ConnectionObject);

	status = EBthConnectionObjectInitializeContinuousReader(
        connection,
		EBthSrvConnectionObjectContReaderReadCompletedCallback,
		EBthSrvConnectionObjectContReaderFailedCallback,
        EBthMaxDataLength
        );

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

	status = EBthConnectionObjectContinuousReaderSubmitReaders(
        connection
        );

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }
exit:
    return status;
}


Вот сам кллбэк - EBthSrvConnectionObjectContReaderReadCompletedCallback,

VOID
EBthSrvConnectionObjectContReaderReadCompletedCallback(
    _In_ PEBTH_DEVICE_CONTEXT_HEADER DevCtxHdr,
	_In_ PEBTH_CONNECTION Connection,
    _In_ PVOID Buffer,
    _In_ size_t BufferLength
    )
/*++
Routine Description:

    This routine is invoked by the continous reader when read completes.

    We in turn call EBthSrvSendEcho to perform echo.

Arguments:

    DevCtxHdr - Device context
    Connection - Connection whose continous reader had read completion
    Bufer - Buffer which received read
    SrcBufferLength - Length of read

--*/
{
	TRACEFUNC();

	EBthSrvSendEcho(
        DevCtxHdr,
        Connection,
        Buffer,
        BufferLength
        );
}


В самой EBthSrvSendEcho идет собственно запихиваание инфы в буфер.

VOID
EBthSrvSendEcho(
    _In_ PEBTH_DEVICE_CONTEXT_HEADER DevCtxHdr,
	_In_ PEBTH_CONNECTION Connection,
    _In_ PVOID SrcBuffer,
    _In_ size_t SrcBufferLength
    )
/*++
Routine Description:

    Performs L2Cap transfer to client to do the echo.
    
    This routine is invoked by continuous reader read completion callback
    (EBthSrvConnectionObjectContReaderReadCompletedCallback).

Arguments:

    DevCtxHdr - Device context
    Connection - Connection whose continous reader had read completion
    SrcBuffer - Source buffer for the echo
    SrcBufferLength - Length of the source buffer

--*/
{
    NTSTATUS status;
    WDF_OBJECT_ATTRIBUTES attributes;
    WDFREQUEST request                  = NULL;
    WDFMEMORY memory                    = NULL;
    PVOID dataBuffer                    = NULL;
    //struct _BRB_L2CA_ACL_TRANSFER *brb  = NULL;
	struct _BRB_SCO_TRANSFER *brb = NULL;

	TRACEFUNC();

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, BRB);
	attributes.ParentObject = DevCtxHdr->Device;

    status = WdfRequestCreate(
        &attributes,
        DevCtxHdr->IoTarget,
        &request
        );
	MyTraceFunc(0, TRACE_LEVEL_VERBOSE, DBG_CONNECT, "WdfRequestCreate:0x%x\n", request);

    if (!NT_SUCCESS(status))
    {
		MyTraceFunc(0, TRACE_LEVEL_ERROR, DBG_CONT_READER,
            "Creating request for echo failed, Status code 0x%x\n",
            status
            );

        goto exit;
    }

    if (SrcBufferLength <= 0) 
    {
		MyTraceFunc(0, TRACE_LEVEL_ERROR, DBG_CONT_READER,
            "SrcBufferLength has an invalid value: %I64d\n",
            SrcBufferLength
            );

        status = STATUS_INVALID_PARAMETER;

        goto exit;
    }

    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    attributes.ParentObject = request;

    status = WdfMemoryCreate(
        &attributes,
        NonPagedPool,
		POOLTAG_EBTH,
        SrcBufferLength,
        &memory,
        &dataBuffer
        );

    if (!NT_SUCCESS(status))
    {
		MyTraceFunc(0, TRACE_LEVEL_ERROR, DBG_CONT_READER,
            "Creating memory for pending read failed, Status code 0x%x\n",
            status
            );

        goto exit;
    }

    memcpy(dataBuffer, SrcBuffer, SrcBufferLength);

    //brb = (struct _BRB_L2CA_ACL_TRANSFER *)GetEchoRequestContext(request);
	brb = (struct _BRB_SCO_TRANSFER *)GetEchoRequestContext(request);

	status = EBthConnectionObjectFormatRequestForL2CaTransfer(
        Connection,
        request,
        &brb,
        memory,
        ACL_TRANSFER_DIRECTION_OUT
        );

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    //
    // Set a CompletionRoutine callback function.
    //
    
    WdfRequestSetCompletionRoutine(
        request,
		EBthSrvWriteCompletion,
        Connection
        );

    if (FALSE == WdfRequestSend(
        request,
        DevCtxHdr->IoTarget,
        NULL
        ))
    {
        status = WdfRequestGetStatus(request);

		MyTraceFunc(0, TRACE_LEVEL_ERROR, DBG_CONT_READER,
            "Request send failed for request 0x%p, Brb 0x%p, Status code 0x%x\n", 
            request,
            brb,
            status
            );

        goto exit;
    }    

exit:
    if (!NT_SUCCESS(status))
    {
        if (NULL != request)
        {
			MyTraceFunc(0, TRACE_LEVEL_VERBOSE, DBG_CONNECT, "WdfObjectDelete:0x%x\n", request);
            WdfObjectDelete(request);
        }

        //
        // If we failed disconnect
        //
		EBthSrvDisconnectConnection(Connection);
    }    
}


Код перенял от коллеги - объяснить он толком ничего не может.

У меня функция EBthSrvSendEcho отрабатывает изредка причем сразу после соединения - но никак не по факту голосовой передачи.

Вопрос главный таков - как отловить событие голосовой передачи - куда вешать коллбэк.

Как взять потоки из наушников ясно.