static HRESULT muteControlHandler(DataStream *pAvcStream, FUNCTION_BLOCK_PARMS *pFbParms, uint32 audioChannel, PB *packetBlock) { uint8 muteValue=0; uint32 fbIDOperand = 4; uint8 fbID = 0; uint32 streamPosMute; // save stream position in case its a status command HRESULT hResult = NO_ERROR; streamPosMute = dsGetPosition(pAvcStream); if (AVC_AUDIO_CHANNEL_MASTER != audioChannel) { hResult = E_PKT_AVC_NOT_IMPLEMENTED; // only one mute is supported, mutes all channels } if (NO_ERROR == hResult) { dsSetPosition(pAvcStream, fbIDOperand); hResult = dsRead8Bits (pAvcStream, &fbID); if (fbID != 1) { hResult = E_PKT_AVC_NOT_IMPLEMENTED; } } if (NO_ERROR == hResult) { /* Switch depending on command type and control attribute. General inquiry CTYPE has been handled at the highest level, so we can ignore that one. */ switch (pFbParms->ctype_attribute) { // ctype GENERAL INQUIRY has been handled already at some higher level // ctype NOTIFY is supported for Current only case CTYPE_ATTRIBUTE (AVC_CTYPE_NOTIFY, AVC_FB_CTRL_ATTRIBUTE_CURRENT): // wants to be 'notified' when current delay changes hResult = postNotifyMute(audioChannel, pFbParms->fbId, packetBlock); if (NO_ERROR == hResult) { hResult = E_PKT_AVC_INTERIM; } break; // ctype CONTROL case CTYPE_ATTRIBUTE (AVC_CTYPE_CONTROL, AVC_FB_CTRL_ATTRIBUTE_CURRENT): // getp the mute parameter dsSetPosition(pAvcStream, fbIDOperand+6); hResult = dsRead8Bits (pAvcStream, &muteValue); SYS_DEBUG(SYSDEBUG_TRACE_AVC_MUSIC, "mute value: %x\n\r", muteValue); if (AVC_AUDIO_MUTE_ON == muteValue) { avsRxMute(0, TRUE); hResult = avrDrdSetMute (TRUE); } else if (AVC_AUDIO_MUTE_OFF == muteValue) { avsRxMute(0, FALSE); hResult = avrDrdSetMute (FALSE); } if (NO_ERROR == hResult) { // all ok, return 'accepted' to avc_main and avc_main will send the response hResult = E_PKT_AVC_ACCEPTED; } break; // ctype STATUS case CTYPE_ATTRIBUTE (AVC_CTYPE_STATUS, AVC_FB_CTRL_ATTRIBUTE_CURRENT): dsSetPosition(pAvcStream, streamPosMute); hResult = dsSwitchMode(pAvcStream, dsMODE_WRITE); if (NO_ERROR == hResult) { if (avrDrdHostState.mute) { hResult = dsWrite8Bits (pAvcStream, AVC_AUDIO_MUTE_ON); } else { hResult = dsWrite8Bits (pAvcStream, AVC_AUDIO_MUTE_OFF); } } if (NO_ERROR == hResult) { // all ok, return 'stable' to avc_main and avc_main will send the response hResult = E_PKT_AVC_STABLE; } break; // ctype SPECIFIC INQUIRY case CTYPE_ATTRIBUTE (AVC_CTYPE_SPECIFIC_INQUIRY, AVC_FB_CTRL_ATTRIBUTE_CURRENT): hResult = E_PKT_AVC_IMPLEMENTED; break; default: hResult = E_PKT_AVC_NOT_IMPLEMENTED; break; } } return(hResult); }
HRESULT avcCmdSignalSource(AVC_HEADER *pHeader, PB *packetBlock, pDataStream pStream) { HRESULT hResultError = E_PKT_AVC_NOT_IMPLEMENTED; HRESULT hResult = NO_ERROR; uint8 inByte = 0; uint16 inVal = 0; uint8 dest_su = 0; uint8 dest_plug_id = 0; uint8 source_su = 0; uint8 source_plug_id = 0; uint8 status = 0; AVC_SIGNAL_PATH *path = NULL; switch (pHeader->ctype) { case AVC_CTYPE_NOTIFY: // - : M:Mandatory, R:Recommended, O:Optional, -:Not Defined hResultError = E_PKT_AVC_REJECTED; break; case AVC_CTYPE_STATUS: // - : M:Mandatory, R:Recommended, O:Optional, -:Not Defined hResultError = E_PKT_AVC_REJECTED; // operand[0,1]: 0xFFFF hResult = dsRead16Bits(pStream, &inVal); if (hResult != NO_ERROR) return hResultError; if (inVal != 0xFFFF) return hResultError; // operand[2]: 0xFE hResult = dsRead8Bits(pStream, &inByte); if (hResult != NO_ERROR) return hResultError; if (inByte != 0xFE) return hResultError; // operand[3]: signal_dest_su hResult = dsRead8Bits(pStream, &dest_su); if (hResult != NO_ERROR) return hResultError; // operand[4]: signal_dest_plug_id hResult = dsRead8Bits(pStream, &dest_plug_id); if (hResult != NO_ERROR) return hResultError; // incoming status command has parsed successfully SYS_DEBUG(SYSDEBUG_TRACE_AVC_MUSIC, "Sig Src status: dest_su: 0x%02x, dest_plug_id 0x%02x\n\r", dest_su, dest_plug_id); hResult = targetSignalSourceFindPath(dest_plug_id, dest_su, &source_plug_id, &source_su, &status, &path); if (NO_ERROR != hResult) { return E_PKT_AVC_REJECTED; } // reply with the appropriate contents - go back to beginning of operand[0] hResult = dsGotoMarker(pStream, DSMARKER_OPERAND_0); if (hResult != NO_ERROR) return hResultError; hResult = dsSwitchMode(pStream, dsMODE_WRITE); if (hResult != NO_ERROR) return hResultError; // operand[0]: 3:output_status, 1:conv, 4:signal_status hResult = dsWrite8Bits(pStream, status); if (hResult != NO_ERROR) return hResultError; // operand[1]: source_su hResult = dsWrite8Bits(pStream, source_su); if (hResult != NO_ERROR) return hResultError; // operand[2]: source_plug_id hResult = dsWrite8Bits(pStream, source_plug_id); if (hResult != NO_ERROR) return hResultError; // operand[3]: dest_su hResult = dsWrite8Bits(pStream, dest_su); if (hResult != NO_ERROR) return hResultError; // operand[4]: dest_plug_id hResult = dsWrite8Bits(pStream, dest_plug_id); if (hResult != NO_ERROR) return hResultError; if (pHeader->ctype == AVC_CTYPE_STATUS) { hResult = E_PKT_AVC_STABLE; } break; case AVC_CTYPE_SPECIFIC_INQUIRY: // asking if a plug is a possible clock sync source case AVC_CTYPE_CONTROL: // setting the clock sync source to a plug { BYTE src_su = 0; BYTE src_plug_id = 0; BYTE dst_su = 0; BYTE dst_plug_id = 0; hResultError = E_PKT_AVC_NOT_IMPLEMENTED; // operand[1]: 0x0F hResult = dsRead8Bits(pStream, &inByte); if (hResult != NO_ERROR) return hResultError; // operand[2]: signal_src subunit hResult = dsRead8Bits(pStream, &src_su); if (hResult != NO_ERROR) return hResultError; // operand[3]: signal_src plug id hResult = dsRead8Bits(pStream, &src_plug_id); if (hResult != NO_ERROR) return hResultError; // operand[4]: signal_dest subunit hResult = dsRead8Bits(pStream, &dst_su); if (hResult != NO_ERROR) return hResultError; // operand[5]: signal_dest plug id hResult = dsRead8Bits(pStream, &dst_plug_id); if (hResult != NO_ERROR) return hResultError; SYS_DEBUG(SYSDEBUG_TRACE_AVC_MUSIC, "Sig Src s_su 0x%02x, s_id 0x%02x, d_su 0x%02x, d_id 0x%02x\n\r", src_su, src_plug_id, dst_su, dst_plug_id); if ( avcDriverPlugIsSyncPath(dst_su, dst_plug_id, src_su, src_plug_id) ) { // host is asking if it can connect a unit input plug to a subunit output plug (i.e. for sync) hResult = dsGotoMarker(pStream, DSMARKER_OPERAND_0); if (hResult != NO_ERROR) return hResultError; hResult = dsSwitchMode(pStream, dsMODE_WRITE); if (hResult != NO_ERROR) return hResultError; hResult = dsWrite8Bits(pStream, 0x00); // accepted if (hResult != NO_ERROR) return hResultError; hResult = dsWrite8Bits(pStream, 0xff); if (hResult != NO_ERROR) return hResultError; if (AVC_CTYPE_SPECIFIC_INQUIRY == pHeader->ctype) { SYS_DEBUG(SYSDEBUG_TRACE_AVC_MUSIC, " accepted clock source inquiry, src_plug_id: %d\n\r", src_plug_id); return E_PKT_AVC_ACCEPTED; } else if (AVC_CTYPE_CONTROL == pHeader->ctype) // set clock source { hResult = avcDriverSetClockSrc(src_su, src_plug_id); if (hResult != NO_ERROR) return hResultError; SYS_DEBUG(SYSDEBUG_TRACE_AVC_MUSIC, " accepted set clock source, src_plug_id: %d\n\r", src_plug_id); } return E_PKT_AVC_ACCEPTED; } SYS_DEBUG(SYSDEBUG_TRACE_AVC_MUSIC, " rejected clock source inquiry\n\r"); hResult = E_PKT_AVC_REJECTED; } break; case AVC_CTYPE_GENERAL_INQUIRY: // don't even bother parsing hResult = E_PKT_AVC_IMPLEMENTED; break; default: hResult = hResultError; break; } return hResult; }
static HRESULT delayControlHandler(DataStream *pAvcStream, FUNCTION_BLOCK_PARMS *pFbParms, uint32 audioChannel, PB *packetBlock) { uint8 valueMsb=0; uint8 valueLsb=0; uint32 streamPosDelay; // save stream position in case its a status command HRESULT hResult=NO_ERROR; streamPosDelay = dsGetPosition(pAvcStream); if (AVC_AUDIO_CHANNEL_MASTER == audioChannel) { hResult = E_PKT_AVC_NOT_IMPLEMENTED; // delay is not available on master channel } // trap the delay parameters if (NO_ERROR == hResult) { hResult = dsRead8Bits (pAvcStream, &valueMsb); if (NO_ERROR == hResult) { hResult = dsRead8Bits (pAvcStream, &valueLsb); } } if (NO_ERROR == hResult) { /* diverge again, depending on command type and control attribute. General inquiry CTYPE has been handled at the highest level, so we can ignore that one. */ switch (pFbParms->ctype_attribute) { // ctype GENERAL INQUIRY has been handled already at some higher level // ctype NOTIFY is supported for Current only case CTYPE_ATTRIBUTE (AVC_CTYPE_NOTIFY, AVC_FB_CTRL_ATTRIBUTE_CURRENT): // wants to be 'notified' when current delay changes hResult = postNotifyDelay(audioChannel, pFbParms->fbId, packetBlock); if (NO_ERROR == hResult) { hResult = E_PKT_AVC_INTERIM; } break; // ctype CONTROL case CTYPE_ATTRIBUTE (AVC_CTYPE_CONTROL, AVC_FB_CTRL_ATTRIBUTE_CURRENT): // change current delay for a channel { uint32 delay = (valueMsb << 8) + valueLsb; hResult = avrDrdSetAudioDelay (delay, audioChannel); if (NO_ERROR == hResult) { hResult = E_PKT_AVC_ACCEPTED; } break; } // ctype STATUS case CTYPE_ATTRIBUTE (AVC_CTYPE_STATUS, AVC_FB_CTRL_ATTRIBUTE_CURRENT): /* get the requested delay and write it into the packet block at the previously saved location, overwriting the delay field */ { uint32 delay; delay = avrDrdHostState.audioDelays[audioChannel]; valueMsb = (uint8)((delay >> 8) & 0xFF); valueLsb = (uint8)(delay & 0xFF); dsSetPosition(pAvcStream, streamPosDelay); hResult = dsSwitchMode(pAvcStream, dsMODE_WRITE); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, valueMsb); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, valueLsb); } } if (NO_ERROR == hResult) { // all ok, return 'stable' to avc_main and avc_main will send the response hResult = E_PKT_AVC_STABLE; } break; } // ctype SPECIFIC INQUIRY case CTYPE_ATTRIBUTE (AVC_CTYPE_SPECIFIC_INQUIRY, AVC_FB_CTRL_ATTRIBUTE_DELTA): case CTYPE_ATTRIBUTE (AVC_CTYPE_SPECIFIC_INQUIRY, AVC_FB_CTRL_ATTRIBUTE_CURRENT): hResult = E_PKT_AVC_IMPLEMENTED; break; default: hResult = E_PKT_AVC_NOT_IMPLEMENTED; break; } } return(hResult); }
static HRESULT volumeControlHandler(DataStream *pAvcStream, FUNCTION_BLOCK_PARMS *pFbParms, uint32 audioChannel, PB *packetBlock) { uint8 valueMsb=0; uint8 valueLsb=0; uint32 streamPosVolume; // save stream position in case its a status command HRESULT hResult = NO_ERROR; streamPosVolume = dsGetPosition(pAvcStream); // trap the volume parameters hResult = dsRead8Bits (pAvcStream, &valueMsb); if (NO_ERROR == hResult) { hResult = dsRead8Bits (pAvcStream, &valueLsb); } if (NO_ERROR == hResult) { /* diverge again, depending on command type and control attribute. General inquiry CTYPE has been handled at the highest level, so we can ignore that one. */ switch (pFbParms->ctype_attribute) { // ctype GENERAL INQUIRY has been handled already at some higher level // ctype NOTIFY is supported for Current only case CTYPE_ATTRIBUTE (AVC_CTYPE_NOTIFY, AVC_FB_CTRL_ATTRIBUTE_CURRENT): // wants to be 'notified' when current volume changes hResult = postNotifyVolume(audioChannel, pFbParms->fbId, packetBlock); if (NO_ERROR == hResult) { hResult = E_PKT_AVC_INTERIM; } break; // ctype CONTROL case CTYPE_ATTRIBUTE (AVC_CTYPE_CONTROL, AVC_FB_CTRL_ATTRIBUTE_DELTA): // relative change in volume { int16 relativeVolume = (int16)((valueMsb << 8) + valueLsb); // signed value /* Request is a relative change, based on a 16-bit signed value. We will convert this to an absolute volume value and set it as such for the appropriate channel. */ if (AVC_AUDIO_CHANNEL_MASTER == audioChannel) { hResult = avrDrdSetMasterVolume ( (uint32)(avrDrdHostState.masterVolume + relativeVolume)); } else { hResult = avrDrdSetTrimVolume ( (uint32)(avrDrdHostState.masterVolume + relativeVolume), audioChannel); } if (NO_ERROR == hResult) { hResult = E_PKT_AVC_ACCEPTED; } } break; case CTYPE_ATTRIBUTE (AVC_CTYPE_CONTROL, AVC_FB_CTRL_ATTRIBUTE_CURRENT): // absolute change in volume { uint32 absoluteVolume = (valueMsb << 8) + valueLsb; if (AVC_AUDIO_CHANNEL_MASTER == audioChannel) { hResult = avrDrdSetMasterVolume (absoluteVolume); } else { hResult = avrDrdSetTrimVolume (absoluteVolume, audioChannel); } if (NO_ERROR == hResult) { hResult = E_PKT_AVC_ACCEPTED; } } break; // ctype STATUS case CTYPE_ATTRIBUTE (AVC_CTYPE_STATUS, AVC_FB_CTRL_ATTRIBUTE_CURRENT): /* get the requested volume and write it into the packet block at the previously saved location, overwriting the volume field */ { uint32 volume; if (AVC_AUDIO_CHANNEL_MASTER == audioChannel) { volume = avrDrdHostState.masterVolume; } else { volume = avrDrdHostState.trimVolume[audioChannel]; } valueMsb = (uint8)((volume >> 8) & 0xFF); valueLsb = (uint8)(volume & 0xFF); dsSetPosition(pAvcStream, streamPosVolume); hResult = dsSwitchMode(pAvcStream, dsMODE_WRITE); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, valueMsb); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, valueLsb); } } if (NO_ERROR == hResult) { // all ok, return 'stable' to avc_main and avc_main will send the response hResult = E_PKT_AVC_STABLE; } } break; // ctype STATUS case CTYPE_ATTRIBUTE (AVC_CTYPE_STATUS, AVC_FB_CTRL_ATTRIBUTE_RESOLUTION): /* get the requested value and write it into the packet block at the previously saved location, overwriting the return parameter field */ { dsSetPosition(pAvcStream, streamPosVolume); hResult = dsSwitchMode(pAvcStream, dsMODE_WRITE); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, 0x01); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, 0x00); } } if (NO_ERROR == hResult) { // all ok, return 'stable' to avc_main and avc_main will send the response hResult = E_PKT_AVC_STABLE; } } break; // ctype STATUS case CTYPE_ATTRIBUTE (AVC_CTYPE_STATUS, AVC_FB_CTRL_ATTRIBUTE_MINIMUM): /* get the requested value and write it into the packet block at the previously saved location, overwriting the return parameter field */ { dsSetPosition(pAvcStream, streamPosVolume); hResult = dsSwitchMode(pAvcStream, dsMODE_WRITE); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, 0x89); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, 0x00); } } if (NO_ERROR == hResult) { // all ok, return 'stable' to avc_main and avc_main will send the response hResult = E_PKT_AVC_STABLE; } } break; // ctype STATUS case CTYPE_ATTRIBUTE (AVC_CTYPE_STATUS, AVC_FB_CTRL_ATTRIBUTE_MAXIMUM): /* get the requested value and write it into the packet block at the previously saved location, overwriting the return parameter field */ { dsSetPosition(pAvcStream, streamPosVolume); hResult = dsSwitchMode(pAvcStream, dsMODE_WRITE); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, 0x00); if (NO_ERROR == hResult) { hResult = dsWrite8Bits (pAvcStream, 0x00); } } if (NO_ERROR == hResult) { // all ok, return 'stable' to avc_main and avc_main will send the response hResult = E_PKT_AVC_STABLE; } } break; // ctype SPECIFIC INQUIRY case CTYPE_ATTRIBUTE (AVC_CTYPE_SPECIFIC_INQUIRY, AVC_FB_CTRL_ATTRIBUTE_DELTA): case CTYPE_ATTRIBUTE (AVC_CTYPE_SPECIFIC_INQUIRY, AVC_FB_CTRL_ATTRIBUTE_CURRENT): hResult = E_PKT_AVC_IMPLEMENTED; break; default: hResult = E_PKT_AVC_NOT_IMPLEMENTED; break; } } return(hResult); }
/* Handle the AV/C function block command */ static HRESULT changeConfigurationHandler(DataStream *pAvcStream, AVC_HEADER *pAvcHeaderInfo, PB *pPacketBlock) { uint8 configIdLsb=0; uint8 configIdMsb; uint32 configId; uint32 streamConfigIdPosition; HRESULT hResult = NO_ERROR; UNUSED_ARG(pPacketBlock); // stream is positioned at operand[0], the config id msb streamConfigIdPosition = dsGetPosition(pAvcStream); // extract the config id hResult = dsRead8Bits(pAvcStream, &configIdMsb); if (NO_ERROR == hResult) { hResult = dsRead8Bits(pAvcStream, &configIdLsb); } if (NO_ERROR != hResult) { return(hResult); } configId = (configIdMsb << 8) + configIdLsb; switch (pAvcHeaderInfo->ctype) { case AVC_CTYPE_CONTROL: // tell host to change its mode hResult = avrDrdSetAudioMode (configId); if (NO_ERROR == hResult) { // all ok, return 'accepted' to avc_main and avc_main will send the response hResult = E_PKT_AVC_ACCEPTED; } break; case AVC_CTYPE_STATUS: // send a response with the current configuration configId = avrDrdHostState.audioMode; configIdMsb = (uint8)((configId >> 8) & 0xFF); configIdLsb = (uint8)(configId & 0xFF); // repostion stream at the config id location dsSetPosition(pAvcStream, streamConfigIdPosition); hResult = dsSwitchMode(pAvcStream, dsMODE_WRITE); if (NO_ERROR == hResult) { hResult = dsWrite8Bits(pAvcStream, configIdMsb); if (NO_ERROR == hResult) { hResult = dsWrite8Bits(pAvcStream, configIdLsb); } } if (NO_ERROR == hResult) { // all ok, return 'stable' to avc_main and avc_main will send the response hResult = E_PKT_AVC_STABLE; } break; case AVC_CTYPE_NOTIFY: hResult = AVC_RESPONSE_NOT_IMPLEMENTED; break; case AVC_CTYPE_SPECIFIC_INQUIRY: case AVC_CTYPE_GENERAL_INQUIRY: hResult = AVC_RESPONSE_IMPLEMENTED; break; default: hResult = AVC_RESPONSE_NOT_IMPLEMENTED; break; } return(hResult); }
/* Handle the AV/C function block command */ static HRESULT functionBlockHandler(DataStream *pAvcStream, AVC_HEADER *pAvcHeaderInfo, PB *pPacketBlock) { HRESULT hResult = NO_ERROR; FUNCTION_BLOCK_PARMS fbParms; /* Before peeling the onion some more, check the command type. general inquiry can be executed right here. */ if (AVC_CTYPE_GENERAL_INQUIRY == pAvcHeaderInfo->ctype) { hResult = (AVC_RESPONSE_IMPLEMENTED); goto functionBlockExit; } /* parse common function block parameters. Unfortunately, fb type and id are defined by the spec as possibly being extended, so we need help with these. */ hResult = avcDecodeFunctionBlockType (pAvcStream, &fbParms.fbType); // operand[0] if (NO_ERROR == hResult) { hResult = avcDecodeFunctionBlockID (pAvcStream, &fbParms.fbId); // operand[1] } if (NO_ERROR == hResult) { hResult = dsRead8Bits (pAvcStream, &fbParms.fbAttribute); // operand[2] } if (NO_ERROR == hResult) { // verify that function block in fact does exist if (!functionBlockExists(fbParms.fbType, fbParms.fbId)) { hResult = E_PKT_AVC_REJECTED; } } if (NO_ERROR != hResult) { goto functionBlockExit; } /* combine ctype and attribute into a single 16-bit value */ //KBJ??? ASSERT(256 > pAvcHeaderInfo->ctype); // ctype must be 8-bits max fbParms.ctype_attribute = (CTYPE_ATTRIBUTE)(CTYPE_ATTRIBUTE(pAvcHeaderInfo->ctype, fbParms.fbAttribute)); /* Now we've parsed up to Operand[3]. At this point, handling diverges depending on the function block type. */ switch (fbParms.fbType) { case AVC_FB_TYPE_SELECTOR: hResult = selectorFbHandler(pAvcStream, &fbParms, pAvcHeaderInfo, pPacketBlock); break; case AVC_FB_TYPE_FEATURE: hResult = featureFbHandler(pAvcStream, &fbParms, pAvcHeaderInfo, pPacketBlock); break; case AVC_FB_TYPE_PROCESSING: hResult = processingFbHandler(pAvcStream, &fbParms, pAvcHeaderInfo, pPacketBlock); break; case AVC_FB_TYPE_CODEC: hResult = codecFbHandler(pAvcStream, &fbParms, pAvcHeaderInfo, pPacketBlock); break; case AVC_FB_TYPE_SUBUNIT_DEST_PLUG: case AVC_FB_TYPE_SUBUNIT_SOURCE_PLUG: hResult = E_PKT_AVC_NOT_IMPLEMENTED; break; default: hResult = E_PKT_AVC_NOT_IMPLEMENTED; break; } functionBlockExit: return(hResult); }
static HRESULT featureFbHandler(DataStream *pAvcStream, FUNCTION_BLOCK_PARMS *pFbParms, AVC_HEADER *avcHeaderInfo, PB *pPacketBlock) { HRESULT hResult = NO_ERROR; uint8 featureBlockLength; // Operand[3] uint8 audioChannel=0; // Operand[4] uint8 controlSelector=0; // Operand[5] uint8 controlLength=0; // Operand[6] UNUSED_ARG(avcHeaderInfo); UNUSED_ARG(pPacketBlock); /* trap common operands 3, 4, 5, and 6 */ hResult = dsRead8Bits (pAvcStream, &featureBlockLength); if (NO_ERROR == hResult) { hResult = dsRead8Bits (pAvcStream, &audioChannel); if (NO_ERROR == hResult) { hResult = dsRead8Bits (pAvcStream, &controlSelector); if (NO_ERROR == hResult) { hResult = dsRead8Bits (pAvcStream, &controlLength); } } } if (NO_ERROR == hResult) { if (2 != featureBlockLength) { // operand 3 is always 2 for a feature function block, section 11.3 sysDebugPrintf("avcAudio, feature function block - bad length %d\n\r", featureBlockLength); hResult = E_PKT_AVC_NOT_IMPLEMENTED; } else if(!AudioChannelIsValid(audioChannel)) { sysDebugPrintf("avcAudio, invalid audio channel %d\n\r", audioChannel); hResult = E_PKT_AVC_NOT_IMPLEMENTED; } } if (hResult == NO_ERROR) { /* Now we diverge again, depending on which control is being commanded - datastream is now at start of operand[7] */ switch (controlSelector) { case AVC_AUDIO_VOLUME_CONTROL: if (2 != controlLength) { sysDebugPrintf("avcAudio, volume control - bad control length %d\n\r", controlLength); hResult = E_PKT_AVC_NOT_IMPLEMENTED; } else { hResult = volumeControlHandler(pAvcStream, pFbParms, audioChannel, pPacketBlock); } break; case AVC_AUDIO_MUTE_CONTROL: if (1 != controlLength) { sysDebugPrintf("avcAudio, mute control - bad control length %d\n\r", controlLength); hResult = E_PKT_AVC_NOT_IMPLEMENTED; } else { hResult = muteControlHandler(pAvcStream, pFbParms, audioChannel, pPacketBlock); } break; case AVC_AUDIO_DELAY_CONTROL: if (2 != controlLength) { sysDebugPrintf("avcAudio, delay control - bad control length %d\n\r", controlLength); hResult = E_PKT_AVC_NOT_IMPLEMENTED; } else { hResult = delayControlHandler(pAvcStream, pFbParms, audioChannel, pPacketBlock); } break; default: hResult = E_PKT_AVC_NOT_IMPLEMENTED; break; ; } // switch (controlSelector) } return hResult; }