#include "precomp.h" #include "resource.h" #include "AudioLvl.h" static const int g_nAudIconWidth = 16; static const int g_nAudIconHeight = 16; static const int g_nAudChkbWidth = 13; static const int g_nAudChkbHeight = 13; static const int g_nAudChkbXMargin = 13; static const int g_nAudChkbYMargin = 12; static const int g_nAudIconXMargin = g_nAudChkbXMargin + g_nAudChkbWidth + 3; static const int g_nAudIconYMargin = 10; static const int g_nAudMeterXMargin = g_nAudIconXMargin + g_nAudIconWidth + 5; static const int g_nAudMeterHeight = 7; static const int g_nAudMeterYMargin = g_nAudIconYMargin + (g_nAudMeterHeight/2); static const int g_nAudMeterRightMargin = 5; // 5 pixels from end static const int g_nAudTrkRangeMin = 0; static const int g_nAudTrkRangeMax = 99; static const int g_nAudTrkRangeSeg = 0xFFFF / g_nAudTrkRangeMax; static const int g_nAudTrkTickFreq = 20; static const int g_nAudTrkRightGap = 3; static const int g_nAudTrkXMargin = g_nAudIconXMargin + g_nAudIconWidth + 5; static const int g_nAudTrkYMargin = 2; static const int g_nAudTrkHeight = 25; static const int g_nAudTrkMinWidth = 50; static const int RECTANGLE_WIDTH = 10; static const int RECTANGLE_LEADING = 1; static inline WORD ScaleMixer(DWORD dwVol) { // NOTE: the "+ g_nAudTrkRangeSeg - 1" provides for a correction that // takes place while truncating the position when we are setting the // volume. See bug 1634 return (((LOWORD(dwVol) + g_nAudTrkRangeSeg - 1) * g_nAudTrkRangeMax) / 0xFFFF); } CAudioLevel::CAudioLevel(CAudioControl *pAudioControl) : m_hwndParent(NULL), m_hwndMicTrack(NULL), m_hwndMicTrackTT(NULL), m_hwndSpkTrack(NULL), m_hwndSpkTrackTT(NULL), m_hIconMic(NULL), m_hIconSpkr(NULL), m_hwndChkbRecMute(NULL), m_hwndChkbSpkMute(NULL), m_hwndChkbRecMuteTT(NULL), m_hwndChkbSpkMuteTT(NULL), m_fVisible(FALSE), m_fMicTrkVisible(TRUE), m_fSpkTrkVisible(TRUE), m_dwMicTrackPos(0xFFFFFFFF), m_dwSpkTrackPos(0xFFFFFFFF), m_dwMicLvl(0), m_dwSpkLvl(0), m_hGreyBrush(NULL), m_hBlackBrush(NULL), m_hRedBrush(NULL), m_hGreenBrush(NULL), m_hYellowBrush(NULL), m_hHiLitePen(NULL), m_hShadowPen(NULL), m_hDkShadowPen(NULL), m_hLitePen(NULL) { ClearStruct(&m_rect); m_pAudioControl = pAudioControl; // load icons m_hIconSpkr = (HICON) ::LoadImage( ::GetInstanceHandle(), MAKEINTRESOURCE(IDI_SPKEMPTY), IMAGE_ICON, g_nAudIconWidth, g_nAudIconHeight, LR_DEFAULTCOLOR | LR_SHARED); m_hIconMic = (HICON) ::LoadImage( ::GetInstanceHandle(), MAKEINTRESOURCE(IDI_MICEMPTY), IMAGE_ICON, g_nAudIconWidth, g_nAudIconHeight, LR_DEFAULTCOLOR | LR_SHARED); // create the brushes used for painting the signal level CreateBrushes(); } CAudioLevel::~CAudioLevel() { if (m_hGreyBrush) DeleteObject(m_hGreyBrush); if (m_hRedBrush) DeleteObject(m_hRedBrush); if (m_hYellowBrush) DeleteObject(m_hYellowBrush); if (m_hGreenBrush) DeleteObject(m_hGreenBrush); if (m_hBlackBrush) DeleteObject(m_hBlackBrush); if (m_hHiLitePen) DeleteObject(m_hHiLitePen); if (m_hDkShadowPen) DeleteObject(m_hDkShadowPen); if (m_hShadowPen) DeleteObject(m_hShadowPen); if (m_hLitePen) DeleteObject(m_hLitePen); } CAudioLevel::Create(HWND hwndParent) { BOOL fCanSetRecVolume, fCanSetSpkVolume; BOOL fCheck; m_hwndParent = hwndParent; m_hwndParentParent = GetParent(hwndParent); fCanSetRecVolume = m_pAudioControl->CanSetRecorderVolume(); fCanSetSpkVolume = m_pAudioControl->CanSetSpeakerVolume(); // create the mute check box for microphone m_hwndChkbRecMute = ::CreateWindow( _TEXT("BUTTON"), g_szEmpty, WS_CHILD | WS_CLIPSIBLINGS | BS_AUTOCHECKBOX, 0, 0, 0, 0, m_hwndParent, (HMENU) IDM_MUTE_MICROPHONE, GetInstanceHandle(), NULL); if (m_hwndChkbRecMute != NULL) { // mute is initially off fCheck = !(m_pAudioControl->IsRecMuted()); ::SendMessage(m_hwndChkbRecMute, BM_SETCHECK, fCheck, 0); // create the tool tip m_hwndChkbRecMuteTT = CreateWindowEx(0, TOOLTIPS_CLASS, (LPSTR) NULL, 0, // styles CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hwndParent, (HMENU) NULL, ::GetInstanceHandle(), NULL); if (NULL != m_hwndChkbRecMuteTT) { TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; ti.hwnd = m_hwndParent; ti.hinst = ::GetInstanceHandle(); ti.uId = (UINT) m_hwndChkbRecMute; ti.lpszText = (LPTSTR) IDS_AUDIO_REC_MUTE_TT; ::SendMessage( m_hwndChkbRecMuteTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); } } // create the mute check box for speaker m_hwndChkbSpkMute = ::CreateWindow( _TEXT("BUTTON"), g_szEmpty, WS_CHILD | WS_CLIPSIBLINGS | BS_AUTOCHECKBOX, 0, 0, 0, 0, m_hwndParent, (HMENU) IDM_MUTE_SPEAKER, GetInstanceHandle(), NULL); if (NULL != m_hwndChkbSpkMute) { // set appropriate mute status in microphone's mute check box fCheck = !(m_pAudioControl->IsSpkMuted()); // Mute is off - so check it ::SendMessage(m_hwndChkbSpkMute, BM_SETCHECK, fCheck, 0); // create the tool tip m_hwndChkbSpkMuteTT = CreateWindowEx(0, TOOLTIPS_CLASS, (LPSTR) NULL, 0, // styles CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hwndParent, (HMENU) NULL, ::GetInstanceHandle(), NULL); if (NULL != m_hwndChkbSpkMuteTT) { TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; ti.hwnd = m_hwndParent; ti.hinst = ::GetInstanceHandle(); ti.uId = (UINT) m_hwndChkbSpkMute; ti.lpszText = (LPTSTR) IDS_AUDIO_SPK_MUTE_TT; ::SendMessage( m_hwndChkbSpkMuteTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); } } // create the mic level trackbar: m_hwndMicTrack = ::CreateWindowEx( 0L, TRACKBAR_CLASS, g_szEmpty, WS_CHILD | WS_CLIPSIBLINGS | TBS_HORZ | TBS_NOTICKS | TBS_BOTH | (fCanSetRecVolume ? 0 : WS_DISABLED), 0, 0, 0, 0, m_hwndParent, (HMENU) ID_AUDIODLG_MIC_TRACK, ::GetInstanceHandle(), NULL); if (NULL != m_hwndMicTrack) { ::SendMessage( m_hwndMicTrack, TBM_SETRANGE, FALSE, MAKELONG(g_nAudTrkRangeMin, g_nAudTrkRangeMax)); ::SendMessage( m_hwndMicTrack, TBM_SETTICFREQ, g_nAudTrkTickFreq, g_nAudTrkRangeMin); WORD wPos = (g_nAudTrkRangeMax - g_nAudTrkRangeMin) / 2; if (fCanSetRecVolume) { wPos = ScaleMixer(m_pAudioControl->GetRecorderVolume()); } ::SendMessage( m_hwndMicTrack, TBM_SETPOS, TRUE, wPos); m_hwndMicTrackTT = CreateWindowEx( 0, TOOLTIPS_CLASS, (LPSTR) NULL, 0, // styles CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hwndParent, (HMENU) NULL, ::GetInstanceHandle(), NULL); if (NULL != m_hwndMicTrackTT) { TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; ti.hwnd = m_hwndParent; ti.hinst = ::GetInstanceHandle(); ti.uId = (UINT) m_hwndMicTrack; ti.lpszText = (LPTSTR) IDS_AUDIO_MIC_TRACK_TT; ::SendMessage(m_hwndMicTrackTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); } } // create the speaker level trackbar: m_hwndSpkTrack = ::CreateWindowEx( 0L, TRACKBAR_CLASS, g_szEmpty, WS_CHILD | WS_CLIPSIBLINGS | TBS_HORZ | TBS_NOTICKS | TBS_BOTH | (fCanSetSpkVolume ? 0 : WS_DISABLED), 0, 0, 0, 0, m_hwndParent, (HMENU) ID_AUDIODLG_SPKR_TRACK, ::GetInstanceHandle(), NULL); if (NULL != m_hwndSpkTrack) { ::SendMessage( m_hwndSpkTrack, TBM_SETRANGE, FALSE, MAKELONG(g_nAudTrkRangeMin, g_nAudTrkRangeMax)); ::SendMessage( m_hwndSpkTrack, TBM_SETTICFREQ, g_nAudTrkTickFreq, g_nAudTrkRangeMin); WORD wPos = (g_nAudTrkRangeMax - g_nAudTrkRangeMin) / 2; if (fCanSetSpkVolume) { wPos = ScaleMixer(m_pAudioControl->GetSpeakerVolume()); } ::SendMessage( m_hwndSpkTrack, TBM_SETPOS, TRUE, wPos); m_hwndSpkTrackTT = CreateWindowEx( 0, TOOLTIPS_CLASS, (LPSTR) NULL, 0, // styles CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hwndParent, (HMENU) NULL, ::GetInstanceHandle(), NULL); if (NULL != m_hwndSpkTrackTT) { TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_SUBCLASS | TTF_IDISHWND; ti.hwnd = m_hwndParent; ti.hinst = ::GetInstanceHandle(); ti.uId = (UINT) m_hwndSpkTrack; ti.lpszText = (LPTSTR) IDS_AUDIO_SPK_TRACK_TT; ::SendMessage(m_hwndSpkTrackTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); } } return TRUE; } BOOL CAudioLevel::ForwardSysChangeMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) { CreateBrushes(); if (NULL != m_hwndMicTrack) { ::SendMessage(m_hwndMicTrack, uMsg, wParam, lParam); } if (NULL != m_hwndSpkTrack) { ::SendMessage(m_hwndSpkTrack, uMsg, wParam, lParam); } return TRUE; } BOOL CAudioLevel::CreateBrushes() { // the background color may change on us! COLORREF GreyColor = GetSysColor(COLOR_3DFACE); COLORREF BlackColor = GetSysColor(COLOR_BTNTEXT); const COLORREF RedColor = RGB(255,0,0); const COLORREF YellowColor = RGB(255,255,0); const COLORREF GreenColor = RGB(0,255,0); COLORREF ShadowColor = GetSysColor(COLOR_3DSHADOW); COLORREF HiLiteColor = GetSysColor(COLOR_3DHIGHLIGHT); COLORREF LiteColor = GetSysColor(COLOR_3DLIGHT); COLORREF DkShadowColor = GetSysColor(COLOR_3DDKSHADOW); if (m_hGreyBrush) { DeleteObject(m_hGreyBrush); } m_hGreyBrush = CreateSolidBrush(GreyColor); if (m_hBlackBrush) { DeleteObject(m_hBlackBrush); } m_hBlackBrush = CreateSolidBrush(BlackColor); if (m_hHiLitePen) { DeleteObject(m_hHiLitePen); } m_hHiLitePen = CreatePen(PS_SOLID, 0, HiLiteColor); if (m_hLitePen) { DeleteObject(m_hLitePen); } m_hLitePen = CreatePen(PS_SOLID, 0, LiteColor); if (m_hDkShadowPen) { DeleteObject(m_hDkShadowPen); } m_hDkShadowPen = CreatePen(PS_SOLID, 0, DkShadowColor); if (m_hShadowPen) { DeleteObject(m_hShadowPen); } m_hShadowPen = CreatePen(PS_SOLID, 0, ShadowColor); // red, yellow, green will never change if (!m_hRedBrush) m_hRedBrush = CreateSolidBrush (RedColor); if (!m_hGreenBrush) m_hGreenBrush = CreateSolidBrush(GreenColor); if (!m_hYellowBrush) m_hYellowBrush = CreateSolidBrush(YellowColor); return TRUE; } BOOL CAudioLevel::OnCommand(WPARAM wParam, LPARAM lParam) { LRESULT lCheck; BOOL fSpeaker; switch (LOWORD(wParam)) { default: return FALSE; case IDM_MUTE_MICROPHONE_ACCEL: lCheck = BST_CHECKED; fSpeaker = FALSE; break; case IDM_MUTE_MICROPHONE: lCheck = BST_UNCHECKED; fSpeaker = FALSE; break; case IDM_MUTE_SPEAKER_ACCEL: lCheck = BST_CHECKED; fSpeaker = TRUE; break; case IDM_MUTE_SPEAKER: lCheck = BST_UNCHECKED; fSpeaker = TRUE; break; } BOOL fMute = (lCheck == ::SendMessage( fSpeaker ? m_hwndChkbSpkMute : m_hwndChkbRecMute, BM_GETCHECK, 0, 0)); m_pAudioControl->MuteAudio(fSpeaker, fMute); return TRUE; } BOOL CAudioLevel::ShiftFocus(HWND hwndCur, BOOL fForward) { BOOL bRet = FALSE; HWND aHwnds[] = {m_hwndChkbSpkMute,m_hwndSpkTrack,m_hwndChkbRecMute,m_hwndMicTrack}; int nSizeArray = ARRAY_ELEMENTS(aHwnds); int nIndex, nSelect; HWND hwndNewFocus=NULL; if (m_fVisible) { if (hwndCur == NULL) { hwndNewFocus = m_hwndSpkTrack; } else { for (nIndex = 0; nIndex < nSizeArray; nIndex++) { if (aHwnds[nIndex] == hwndCur) { nSelect = (nIndex + (fForward ? 1 : -1)) % nSizeArray; if (nSelect < 0) nSelect += nSizeArray; hwndNewFocus = aHwnds[nSelect]; break; } } } if (hwndNewFocus) { SetFocus(hwndNewFocus); bRet = TRUE; } } return bRet; } BOOL CAudioLevel::IsChildWindow(HWND hwnd) { if (hwnd) { if ((hwnd == m_hwndSpkTrack) || (hwnd == m_hwndMicTrack) || (hwnd == m_hwndChkbRecMute) || (hwnd == m_hwndChkbSpkMute)) { return TRUE; } } return FALSE; } BOOL CAudioLevel::OnMuteChange(BOOL fSpeaker, BOOL fMute) { SendMessage(fSpeaker ? m_hwndChkbSpkMute : m_hwndChkbRecMute, BM_SETCHECK, fMute ? BST_UNCHECKED : BST_CHECKED, 0); return TRUE; } BOOL CAudioLevel::OnPaint(PAINTSTRUCT* pps) { if (m_fVisible) { ASSERT(pps); ASSERT(pps->hdc); PaintIcons(pps->hdc); } return TRUE; } BOOL CAudioLevel::PaintChannel(BOOL fSpeaker, HDC hdc) { BOOL bGotDC = FALSE; DWORD dwVolume; int nVuWidth, nDiff; RECT rect, rectDraw; HBRUSH hCurrentBrush; HPEN hOldPen; int nRects; int nRectangleWidth; int nIndex; const int NUM_RECTANGLES_MAX = 16; const int NUM_RECTANGLES_MIN = 6; int nRectsTotal; bool bTransmitting; POINT ptOld, pt; if (fSpeaker) { dwVolume = LOWORD(m_dwSpkLvl); bTransmitting = HIWORD(m_dwSpkLvl) & SIGNAL_STATUS_TRANSMIT; } else { dwVolume = LOWORD(m_dwMicLvl); bTransmitting = HIWORD(m_dwMicLvl) & SIGNAL_STATUS_TRANSMIT; } if (!hdc) { if ((fSpeaker) && (m_hwndSpkTrack)) hdc = GetDC(m_hwndSpkTrack); else if (m_hwndMicTrack) hdc = GetDC(m_hwndMicTrack); bGotDC = TRUE; } if (!hdc) return FALSE; // rectangle leading is 1 if (dwVolume > 100) dwVolume = 100; if (fSpeaker) rect = m_rcChannelSpk; else rect = m_rcChannelMic; nVuWidth = rect.right - rect.left; if (nVuWidth < (NUM_RECTANGLES_MIN*2)) return FALSE; // "rect" represents the edges of the meter's outer rectangle // compute the number of individual rectangles to use // we do the computation this way so that sizing the rebar band // makes the size changes consistant nRectsTotal = NUM_RECTANGLES_MAX; nRectsTotal = (nVuWidth + (g_nAudMeterHeight - 1)) / g_nAudMeterHeight; nRectsTotal = min(nRectsTotal, NUM_RECTANGLES_MAX); nRectsTotal = max(nRectsTotal, NUM_RECTANGLES_MIN); // nRectangleWidth - width of colored rectangle - no leading nRectangleWidth = ((nVuWidth-2)/nRectsTotal) - 1; // nVuWidth - width of entire VU meter including edges nVuWidth = (nRectangleWidth + 1)*nRectsTotal + 2; // re-adjust meter size to be an integral number of rects nDiff = rect.right - (rect.left + nVuWidth); rect.right = rect.left + nVuWidth; // center vu-meter across whole channel area so that the // slider's thumb is always covering some portion of the channel rect.left += (nDiff/2); rect.right += (nDiff/2); // draw the 3D frame border hOldPen = (HPEN) SelectObject (hdc, m_hHiLitePen); MoveToEx(hdc, rect.right, rect.top, &ptOld); LineTo(hdc, rect.right, rect.bottom); LineTo(hdc, rect.left-1, rect.bottom); // -1 because LineTo stops just short of this point SelectObject(hdc, m_hShadowPen); MoveToEx(hdc, rect.left, rect.bottom-1, &pt); LineTo(hdc, rect.left, rect.top); LineTo(hdc, rect.right, rect.top); SelectObject(hdc, m_hDkShadowPen); MoveToEx(hdc, rect.left+1, rect.bottom-2, &pt); LineTo(hdc, rect.left+1, rect.top+1); LineTo(hdc, rect.right-1, rect.top+1); SelectObject(hdc, m_hLitePen); MoveToEx(hdc, rect.left+1, rect.bottom-1, &pt); LineTo(hdc, rect.right-1, rect.bottom-1); LineTo(hdc, rect.right-1, rect.top); SelectObject(hdc, m_hShadowPen); // the top and left of the meter has a 2 line border // the bottom and right of the meter has a 2 line border rectDraw.top = rect.top + 2; rectDraw.bottom = rect.bottom - 1 ; rectDraw.left = rect.left + 2; rectDraw.right = rectDraw.left + nRectangleWidth; // how many colored rectangles do we draw ? nRects = (dwVolume * nRectsTotal) / 100; // not transmitting - don't show anything if ((false == bTransmitting) && (false == fSpeaker)) nRects = 0; // transmitting or receiving something very quiet - // light up at least one rectangle else if ((bTransmitting) && (nRects == 0)) nRects = 1; hCurrentBrush = m_hGreenBrush; for (nIndex = 0; nIndex < nRectsTotal; nIndex++) { // far left fourth of the bar is green // right fourth of the bar is red // middle is yellow if (nIndex > ((nRectsTotal*3)/4)) hCurrentBrush = m_hRedBrush; else if (nIndex >= nRectsTotal/2) hCurrentBrush = m_hYellowBrush; if (nIndex >= nRects) hCurrentBrush = m_hGreyBrush; FillRect(hdc, &rectDraw, hCurrentBrush); if (nIndex != (nRectsTotal-1)) { MoveToEx(hdc, rectDraw.left + nRectangleWidth, rectDraw.top, &pt); LineTo(hdc, rectDraw.left + nRectangleWidth, rectDraw.bottom); } rectDraw.left += nRectangleWidth + 1; // +1 for the leading rectDraw.right = rectDraw.left + nRectangleWidth; } MoveToEx(hdc, ptOld.x, ptOld.y, &pt); SelectObject (hdc, hOldPen); if (bGotDC) { DeleteDC(hdc); } return TRUE; } BOOL CAudioLevel::OnTimer(WPARAM wTimerID) { DWORD dwLevel; if (m_fVisible && (NULL != m_pAudioControl)) { dwLevel = m_pAudioControl->GetAudioSignalLevel(FALSE /*fSpeaker*/); // This level ranges from 0-100 if (dwLevel != m_dwMicLvl) { m_dwMicLvl = dwLevel; // HACK: SETRANGEMAX is the only way to force the slider to update itself... SendMessage(m_hwndMicTrack, TBM_SETRANGEMAX, TRUE, g_nAudTrkRangeMax); } dwLevel = m_pAudioControl->GetAudioSignalLevel(TRUE /*fSpeaker*/); // This level ranges from 0-100 if (dwLevel != m_dwSpkLvl) { m_dwSpkLvl = dwLevel; SendMessage(m_hwndSpkTrack, TBM_SETRANGEMAX, TRUE, g_nAudTrkRangeMax); } } return TRUE; } // returns the coordinates of where one of the icons should be drawn BOOL CAudioLevel::GetIconArea(BOOL fSpeaker, RECT *pRect) { int nIconY; int nLeftMic; int nLeftSpk; nIconY = (m_rect.bottom - m_rect.top - g_nAudIconHeight - 1) / 2; pRect->top = m_rect.top + nIconY; pRect->bottom = pRect->top + g_nAudIconHeight; if (fSpeaker) { pRect->left = m_rect.left + ((m_rect.right - m_rect.left) / 2) + g_nAudIconXMargin; } else { pRect->left = m_rect.left + g_nAudIconXMargin; } pRect->right = pRect->left + g_nAudIconWidth; return TRUE; } BOOL CAudioLevel::PaintIcons(HDC hdc) { int nIconY; ASSERT(hdc); RECT rect; if (NULL != m_hIconMic) { GetIconArea(FALSE, &rect); DrawIconEx( hdc, rect.left, rect.top, m_hIconMic, rect.right - rect.left, rect.bottom - rect.top, 0, NULL, DI_NORMAL); } if (NULL != m_hIconSpkr) { GetIconArea(TRUE, &rect); DrawIconEx( hdc, rect.left, rect.top, m_hIconSpkr, rect.right - rect.left, rect.bottom - rect.top, 0, NULL, DI_NORMAL); } return TRUE; } BOOL CAudioLevel::OnDeviceStatusChanged(BOOL fSpeaker, UINT uEvent, UINT uSubCode) { UINT uIconID; HICON *phIcon; UINT *puIconID; RECT rectInvalid; switch (uEvent) { case NM_STREAMEVENT_DEVICE_CLOSED: { uIconID = fSpeaker ? IDI_SPKEMPTY : IDI_MICEMPTY; break; } case NM_STREAMEVENT_DEVICE_OPENED: { uIconID = fSpeaker ? IDI_SPEAKER : IDI_MICFONE; break; } case NM_STREAMEVENT_DEVICE_FAILURE: { uIconID = fSpeaker ? IDI_SPKERROR : IDI_MICERROR; break; } default: return FALSE; } phIcon = fSpeaker ? &m_hIconSpkr : &m_hIconMic; puIconID = fSpeaker ? &m_uIconSpkrID : &m_uIconMicID; if (*puIconID == uIconID) return TRUE; *phIcon = (HICON) ::LoadImage( ::GetInstanceHandle(), MAKEINTRESOURCE(uIconID), IMAGE_ICON, g_nAudIconWidth, g_nAudIconHeight, LR_DEFAULTCOLOR | LR_SHARED); // invalidate the icon regions if (m_hwndParentParent) { RECT rect; GetIconArea(fSpeaker, &rect); ::MapWindowPoints(m_hwndParent, m_hwndParentParent, (LPPOINT) &rect, 2); ::InvalidateRect(m_hwndParentParent, &rect, TRUE /* erase bkgnd */); ::UpdateWindow(m_hwndParentParent); } return TRUE; } BOOL CAudioLevel::Resize(int nLeft, int nTop, int nWidth, int nHeight) { int nCBY, nTBY; // checkbox, trackbar, and Icon y positions // Disable redraws: ASSERT(m_hwndChkbRecMute && m_hwndChkbSpkMute && m_hwndMicTrack && m_hwndSpkTrack); if (m_fVisible) { ::SendMessage(m_hwndChkbRecMute, WM_SETREDRAW, FALSE, 0); ::SendMessage(m_hwndChkbSpkMute, WM_SETREDRAW, FALSE, 0); ::SendMessage(m_hwndMicTrack, WM_SETREDRAW, FALSE, 0); ::SendMessage(m_hwndSpkTrack, WM_SETREDRAW, FALSE, 0); } m_rect.left = nLeft; m_rect.top = nTop; m_rect.right = nLeft + nWidth; m_rect.bottom = nTop + nHeight; nCBY = (m_rect.bottom - m_rect.top - g_nAudChkbHeight) / 2; if (nCBY < 0) nCBY = 0; // "+1" so the trackbar is better centered with the checkbox and icon nTBY = (m_rect.bottom - m_rect.top - g_nAudTrkHeight + 1) / 2; if (nTBY < 0) nTBY = 0; int nHalfPoint = nLeft + (nWidth / 2); if (NULL != m_hwndChkbRecMute) { ::MoveWindow( m_hwndChkbRecMute, nLeft + g_nAudChkbXMargin, nTop + nCBY, g_nAudChkbWidth, g_nAudChkbHeight, TRUE /* repaint */); } if (NULL != m_hwndChkbSpkMute) { ::MoveWindow( m_hwndChkbSpkMute, nHalfPoint + g_nAudChkbXMargin, nTop + nCBY, g_nAudChkbWidth, g_nAudChkbHeight, TRUE /* repaint */); } m_fMicTrkVisible = m_fVisible; if (NULL != m_hwndMicTrack) { int nMicTrkWidth = nHalfPoint - g_nAudTrkRightGap - (nLeft + g_nAudTrkXMargin); ::MoveWindow( m_hwndMicTrack, nLeft + g_nAudTrkXMargin, nTop + nTBY, nMicTrkWidth, g_nAudTrkHeight, FALSE /* don't repaint */); m_fMicTrkVisible = (nMicTrkWidth > g_nAudTrkMinWidth); } m_fSpkTrkVisible = m_fVisible; if (NULL != m_hwndSpkTrack) { int nSpkTrkWidth = nLeft + nWidth - g_nAudTrkRightGap - (nHalfPoint + g_nAudTrkXMargin); ::MoveWindow( m_hwndSpkTrack, nHalfPoint + g_nAudTrkXMargin, nTop + nTBY, nSpkTrkWidth, g_nAudTrkHeight, FALSE /* don't repaint */); m_fSpkTrkVisible = (nSpkTrkWidth > g_nAudTrkMinWidth); } // enable redraws if (m_fVisible) { ::SendMessage(m_hwndChkbRecMute, WM_SETREDRAW, TRUE, 0); ::SendMessage(m_hwndChkbSpkMute, WM_SETREDRAW, TRUE, 0); // Enable redraws: if (m_fMicTrkVisible) { ::SendMessage(m_hwndMicTrack, WM_SETREDRAW, TRUE, 0); } if (m_fSpkTrkVisible) { ::SendMessage(m_hwndSpkTrack, WM_SETREDRAW, TRUE, 0); } // Force the title area to repaint: ::InvalidateRect(m_hwndChkbRecMute, NULL, TRUE /* erase bkgnd */); ::InvalidateRect(m_hwndChkbSpkMute, NULL, TRUE /* erase bkgnd */); ::InvalidateRect(m_hwndMicTrack, NULL, TRUE /* erase bkgnd */); ::InvalidateRect(m_hwndSpkTrack, NULL, TRUE /* erase bkgnd */); ASSERT(m_hwndParent); ASSERT(m_hwndParentParent); RECT rctTemp = m_rect; ::MapWindowPoints(m_hwndParent, m_hwndParentParent, (LPPOINT) &rctTemp, 2); ::InvalidateRect(m_hwndParentParent, &rctTemp, TRUE /* erase bkgnd */); ::UpdateWindow(m_hwndParentParent); } return TRUE; } BOOL CAudioLevel::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *plRet) { LPNMCUSTOMDRAW pCustomDraw; BOOL bRet = FALSE, fSpeaker; RECT *pChannelRect; *plRet = 0; fSpeaker = (wParam == ID_AUDIODLG_SPKR_TRACK); if (fSpeaker) { pChannelRect = &m_rcChannelSpk; } else { pChannelRect = &m_rcChannelMic; } pCustomDraw = (LPNMCUSTOMDRAW)lParam; switch (pCustomDraw->dwDrawStage) { case CDDS_PREPAINT: bRet = TRUE; *plRet = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT; break; case CDDS_ITEMPREPAINT: if (pCustomDraw->dwItemSpec == TBCD_CHANNEL) { *plRet = CDRF_SKIPDEFAULT; bRet = TRUE; pCustomDraw->rc.top -= 2; pCustomDraw->rc.bottom += 2; *pChannelRect = pCustomDraw->rc; PaintChannel(fSpeaker, pCustomDraw->hdc); } break; default: break; } return bRet; } BOOL CAudioLevel::OnScroll(WPARAM wParam, LPARAM lParam) { BOOL bRet = FALSE; if ((HWND) lParam == m_hwndMicTrack) { DWORD dwCurMicTrackPos = ::SendMessage((HWND) lParam, TBM_GETPOS, 0, 0); if (m_dwMicTrackPos != dwCurMicTrackPos) { m_dwMicTrackPos = dwCurMicTrackPos; m_pAudioControl->SetRecorderVolume( (m_dwMicTrackPos * 0xFFFF) / g_nAudTrkRangeMax); } bRet = TRUE; } else if ((HWND) lParam == m_hwndSpkTrack) { DWORD dwCurSpkTrackPos = ::SendMessage((HWND) lParam, TBM_GETPOS, 0, 0); if (m_dwSpkTrackPos != dwCurSpkTrackPos) { m_dwSpkTrackPos = dwCurSpkTrackPos; m_pAudioControl->SetSpeakerVolume( (m_dwSpkTrackPos * 0xFFFF) / g_nAudTrkRangeMax); } bRet = TRUE; } return bRet; } BOOL CAudioLevel::OnLevelChange(BOOL fSpeaker, DWORD dwVolume) { if (fSpeaker) { if (NULL != m_hwndSpkTrack) { DWORD dwTrackPos = ScaleMixer(dwVolume); if (m_dwSpkTrackPos != dwTrackPos) { m_dwSpkTrackPos = dwTrackPos; TRACE_OUT(("Setting Spk Volume to %d", m_dwSpkTrackPos)); ::SendMessage( m_hwndSpkTrack, TBM_SETPOS, TRUE, m_dwSpkTrackPos); } } } else { if (NULL != m_hwndMicTrack) { DWORD dwTrackPos = ScaleMixer(dwVolume); if (m_dwMicTrackPos != dwTrackPos) { m_dwMicTrackPos = dwTrackPos; TRACE_OUT(("Setting Mic Volume to %d", m_dwMicTrackPos)); ::SendMessage( m_hwndMicTrack, TBM_SETPOS, TRUE, m_dwMicTrackPos); } } } return TRUE; } BOOL CAudioLevel::OnDeviceChanged(void) { ASSERT(m_pAudioControl); EnableWindow(m_hwndMicTrack, m_pAudioControl->CanSetRecorderVolume()); EnableWindow(m_hwndSpkTrack, m_pAudioControl->CanSetSpeakerVolume()); return TRUE; } BOOL CAudioLevel::Show(BOOL fVisible) { m_fVisible = fVisible; if (m_fVisible) { // Start mic sensitivity timer: ::SetTimer(m_hwndParent, AUDIODLG_MIC_TIMER, AUDIODLG_MIC_TIMER_PERIOD, NULL); } else { // Stop mic sensitivity timer: ::KillTimer(m_hwndParent, AUDIODLG_MIC_TIMER); } // Hide or show all windows: if (NULL != m_hwndChkbRecMute) { ::ShowWindow(m_hwndChkbRecMute, fVisible ? SW_SHOW : SW_HIDE); } if (NULL != m_hwndChkbSpkMute) { ::ShowWindow(m_hwndChkbSpkMute, fVisible ? SW_SHOW : SW_HIDE); } if (NULL != m_hwndMicTrack) { ::ShowWindow(m_hwndMicTrack, (fVisible && m_fMicTrkVisible) ? SW_SHOW : SW_HIDE); } if (NULL != m_hwndSpkTrack) { ::ShowWindow(m_hwndSpkTrack, (fVisible && m_fSpkTrkVisible) ? SW_SHOW : SW_HIDE); } return TRUE; }